Skip to content

Commit

Permalink
Merge pull request #402 from spacious-team/develop
Browse files Browse the repository at this point in the history
Релиз 2022.1
  • Loading branch information
vananiev authored Jan 16, 2022
2 parents 272fc1a + 9acb7cf commit 3bf964b
Show file tree
Hide file tree
Showing 44 changed files with 1,092 additions and 483 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
в сравнении с S&P 500, история инвестиций и остатка денежных средств;
![portfolio-analysis](https://user-images.githubusercontent.com/11336712/102415874-fd17a280-4009-11eb-9bff-232975adf21b.png)
<img src="https://user-images.githubusercontent.com/11336712/102416414-d4dc7380-400a-11eb-95b1-8ff8ae37bd17.png" width="32%"/>
<img src="https://user-images.githubusercontent.com/11336712/102415878-fee16600-4009-11eb-87c5-ed4ac6629941.png" width="32%"/>
<img src="https://user-images.githubusercontent.com/11336712/149419132-cad11fc3-fdaa-4572-882b-4ed49b937afe.png" width="32%"/>
<img src="https://user-images.githubusercontent.com/11336712/102419341-9a75d500-4010-11eb-817a-a9b322237dd2.png" width="32%"/>
- [портфель](src/main/asciidoc/portfolio-status.adoc) ценных бумаг с информацией о текущей позиции, усредненной цене
покупок и доходности ценных бумаг (ЧИСТВНДОХ/XIRR) с учетом хеджирующих позиций на срочном рынке и усредненной цены покупки валюты;
Expand Down
10 changes: 5 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</parent>
<groupId>ru.investbook</groupId>
<artifactId>investbook</artifactId>
<version>2021.11</version>
<version>2022.1</version>

<name>investbook</name>
<description>Investor Accounting Book</description>
Expand All @@ -47,7 +47,7 @@

<properties>
<!-- Valid version is (0-255).(0-255).(0-65535) -->
<win.msi.version>21.11</win.msi.version>
<win.msi.version>22.1</win.msi.version>
<java.version>17</java.version>
<!-- version 3.2.0 provided by Spring Boot 2.4.1 has bug, using version from Spring Boot 2.3.4
TODO remove after fix -->
Expand Down Expand Up @@ -83,7 +83,7 @@
<dependency>
<groupId>com.github.spacious-team</groupId>
<artifactId>broker-report-parser-api</artifactId>
<version>2021.11</version>
<version>2022.1</version>
</dependency>
<dependency>
<groupId>com.github.spacious-team</groupId>
Expand Down Expand Up @@ -143,7 +143,7 @@
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.4.0</version>
<version>7.5</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -174,7 +174,7 @@
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.2</version>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
Expand Down
2 changes: 1 addition & 1 deletion src/main/asciidoc/portfolio-analysis.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,5 @@ https://fs.moex.com/files/3344[делителя] `D`. Суть делителя


image::102416414-d4dc7380-400a-11eb-95b1-8ff8ae37bd17.png[Пример графика Активов и инвестиций]
image::102415878-fee16600-4009-11eb-87c5-ed4ac6629941.png[Пример графика Роста активов]
image::149419132-cad11fc3-fdaa-4572-882b-4ed49b937afe.png[Пример графика Роста активов]
image::102419341-9a75d500-4010-11eb-817a-a9b322237dd2.png[Пример графика Остатка денежных средств]
91 changes: 91 additions & 0 deletions src/main/java/db/migration/all/V2022_1_0_1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* InvestBook
* Copyright (C) 2022 Vitalii Ananev <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package db.migration.all;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;

import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Collections;

@Slf4j
public class V2022_1_0_1 extends BaseJavaMigration {

public void migrate(Context context) throws Exception {
try (Statement select = context.getConnection().createStatement()) {
try (ResultSet rows = select.executeQuery("SELECT * FROM `portfolio_property` WHERE `property` = 'CASH'")) {
ObjectMapper objectMapper = new ObjectMapper();
while (rows.next()) {
String portfolio = rows.getString("portfolio");
Timestamp timestamp = rows.getTimestamp("timestamp");
String value = rows.getString("value");
Collection<PortfolioCash> cashCollection = PortfolioCash.deserialize(objectMapper, value);
try (Statement statement = context.getConnection().createStatement()) {
cashCollection.forEach(cash -> insertCash(statement, portfolio, timestamp, cash));
}
}
}
}
try (Statement delete = context.getConnection().createStatement()) {
delete.execute("DELETE FROM `portfolio_property` WHERE `property` = 'CASH'");
}
}

private void insertCash(Statement statement, String portfolio, Timestamp timestamp, PortfolioCash cash) {
try {
statement.execute("INSERT INTO `portfolio_cash` SET " +
"portfolio ='" + portfolio + "', " +
"timestamp = '" + timestamp + "', " +
"market = '" + cash.getSection() + "', " +
"value = " + cash.getValue() + ", " +
"currency = '" + cash.getCurrency() + "'");
} catch (Exception e) {
log.error("can't insert to table 'cash' value: portfolio = {}, timestamp = {}, cash = {}",
portfolio, timestamp, cash, e);
}
}


@Getter
@Setter
private static class PortfolioCash {
private String section;
private BigDecimal value;
private String currency;

public static Collection<PortfolioCash> deserialize(ObjectMapper objectMapper, String value) {
try {
return objectMapper.readValue(value, new TypeReference<>() {
});
} catch (Exception e) {
log.error("can't deserialize portfolio cash", e);
return Collections.emptySet();
}
}
}
}
113 changes: 113 additions & 0 deletions src/main/java/ru/investbook/api/PortfolioCashRestController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* InvestBook
* Copyright (C) 2021 Vitalii Ananev <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package ru.investbook.api;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.spacious_team.broker.pojo.PortfolioCash;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ru.investbook.converter.EntityConverter;
import ru.investbook.entity.PortfolioCashEntity;

import javax.validation.Valid;
import java.util.List;
import java.util.Optional;

@RestController
@Tag(name = "Информация по остатку денежных средств на счете")
@RequestMapping("/api/v1/portfolio-cash")
public class PortfolioCashRestController extends AbstractRestController<Integer, PortfolioCash, PortfolioCashEntity> {

public PortfolioCashRestController(JpaRepository<PortfolioCashEntity, Integer> repository,
EntityConverter<PortfolioCashEntity, PortfolioCash> converter) {
super(repository, converter);
}

@Override
@GetMapping
@Operation(summary = "Отобразить все", description = "Отображает всю имеющуюся информацию обо всех счетах")
public List<PortfolioCash> get() {
return super.get();
}

@Override
@GetMapping("{id}")
@Operation(summary = "Отобразить один", description = "Отображает информацию по идентификатору")
public ResponseEntity<PortfolioCash> get(@PathVariable("id")
@Parameter(description = "Внутренний идентификатор записи")
Integer id) {
return super.get(id);
}

@Override
@PostMapping
@Operation(summary = "Добавить", description = "Добавить информацию для конкретного счета")
public ResponseEntity<Void> post(@Valid @RequestBody PortfolioCash property) {
return super.post(property);
}

@Override
@PutMapping("{id}")
@Operation(summary = "Обновить", description = "Обновить информацию для счета")
public ResponseEntity<Void> put(@PathVariable("id")
@Parameter(description = "Внутренний идентификатор записи")
Integer id,
@Valid @RequestBody PortfolioCash property) {
return super.put(id, property);
}

@Override
@DeleteMapping("{id}")
@Operation(summary = "Удалить")
public void delete(@PathVariable("id")
@Parameter(description = "Внутренний идентификатор записи")
Integer id) {
super.delete(id);
}

@Override
protected Optional<PortfolioCashEntity> getById(Integer id) {
return repository.findById(id);
}

@Override
protected Integer getId(PortfolioCash object) {
return object.getId();
}

@Override
protected PortfolioCash updateId(Integer id, PortfolioCash object) {
return object.toBuilder().id(id).build();
}

@Override
protected String getLocation() {
return "/portfolio-cash";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ public ResponseEntity<PortfolioProperty> get(@PathVariable("id")

@Override
@PostMapping
@Operation(summary = "Добавить", description = "Добавить информацию о конкретном счете")
@Operation(summary = "Добавить", description = "Добавить информацию для конкретного счета")
public ResponseEntity<Void> post(@Valid @RequestBody PortfolioProperty property) {
return super.post(property);
}

@Override
@PutMapping("{id}")
@Operation(summary = "Обновить", description = "Обновить информацию о счете")
@Operation(summary = "Обновить", description = "Обновить информацию для счета")
public ResponseEntity<Void> put(@PathVariable("id")
@Parameter(description = "Внутренний идентификатор записи")
Integer id,
Expand Down
51 changes: 51 additions & 0 deletions src/main/java/ru/investbook/converter/PortfolioCashConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* InvestBook
* Copyright (C) 2020 Vitalii Ananev <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package ru.investbook.converter;

import org.spacious_team.broker.pojo.PortfolioCash;
import org.springframework.stereotype.Component;
import ru.investbook.entity.PortfolioCashEntity;

@Component
public class PortfolioCashConverter implements EntityConverter<PortfolioCashEntity, PortfolioCash> {

@Override
public PortfolioCashEntity toEntity(PortfolioCash cash) {
PortfolioCashEntity entity = new PortfolioCashEntity();
entity.setId(cash.getId());
entity.setPortfolio(cash.getPortfolio());
entity.setMarket(cash.getMarket());
entity.setTimestamp(cash.getTimestamp());
entity.setValue(cash.getValue());
entity.setCurrency(cash.getCurrency());
return entity;
}

@Override
public PortfolioCash fromEntity(PortfolioCashEntity entity) {
return PortfolioCash.builder()
.id(entity.getId())
.portfolio(entity.getPortfolio())
.market(entity.getMarket())
.timestamp(entity.getTimestamp())
.value(entity.getValue())
.currency(entity.getCurrency())
.build();
}
}
63 changes: 63 additions & 0 deletions src/main/java/ru/investbook/entity/PortfolioCashEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* InvestBook
* Copyright (C) 2020 Vitalii Ananev <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package ru.investbook.entity;

import lombok.Data;
import org.hibernate.annotations.GenericGenerator;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.math.BigDecimal;
import java.time.Instant;

@Entity
@Table(name = "portfolio_cash")
@Data
public class PortfolioCashEntity {

@Id
@GenericGenerator(name = "UseExistingOrGenerateIdGenerator", strategy = "ru.investbook.entity.UseExistingOrGenerateIdGenerator")
@GeneratedValue(generator = "UseExistingOrGenerateIdGenerator")
@Column(name = "id")
private Integer id;

@Basic
@Column(name = "portfolio", nullable = false)
private String portfolio;

@Basic
@Column(name = "timestamp", nullable = false)
private Instant timestamp;

@Basic
@Column(name = "market")
private String market;

@Basic
@Column(name = "value", nullable = false)
private BigDecimal value;

@Basic
@Column(name = "currency", nullable = false)
private String currency;
}
Loading

0 comments on commit 3bf964b

Please sign in to comment.