1
0

Compare commits

...

5 Commits

23 changed files with 1489 additions and 327 deletions

View File

@@ -1,5 +1,6 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="AUTODETECT_INDENTS" value="false" />
<JSCodeStyleSettings version="0">
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
<option name="FORCE_SEMICOLON_STYLE" value="true" />
@@ -27,6 +28,9 @@
<ScalaCodeStyleSettings>
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
</ScalaCodeStyleSettings>
<SqlCodeStyleSettings version="7">
<option name="KEYWORD_CASE" value="1" />
</SqlCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="USE_SEMICOLON_AFTER_STATEMENT" value="false" />
<option name="FORCE_SEMICOLON_STYLE" value="true" />
@@ -73,6 +77,15 @@
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="SQL">
<option name="KEEP_LINE_BREAKS" value="false" />
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
@@ -91,5 +104,10 @@
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
<codeStyleSettings language="yaml">
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
<option name="LINE_COMMENT_ADD_SPACE" value="true" />
<option name="LINE_COMMENT_ADD_SPACE_ON_REFORMAT" value="true" />
</codeStyleSettings>
</code_scheme>
</component>

4
.idea/dataSources.xml generated
View File

@@ -39,11 +39,11 @@
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
<data-source source="LOCAL" name="leopard@81.71.3.24" uuid="4b5dd0f8-26c8-49e2-b794-d464461c121a">
<data-source source="LOCAL" name="leopard_dev@81.71.3.24" uuid="63824900-a456-4883-8de4-8f436cd00c71">
<driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
<jdbc-url>jdbc:postgresql://81.71.3.24:6785/leopard</jdbc-url>
<jdbc-url>jdbc:postgresql://81.71.3.24:6785/leopard_dev</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />

View File

@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourcePerFileMappings">
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/4b5dd0f8-26c8-49e2-b794-d464461c121a/console.sql" value="4b5dd0f8-26c8-49e2-b794-d464461c121a" />
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/a8b9cd0a-335e-42ae-991a-f2733200afbf/console.sql" value="a8b9cd0a-335e-42ae-991a-f2733200afbf" />
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/f7d817dc-8c9c-479f-b469-583df17cb013/console.sql" value="f7d817dc-8c9c-479f-b469-583df17cb013" />
</component>
</project>

View File

@@ -24,6 +24,17 @@
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-ant</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@@ -10,6 +10,7 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
@@ -29,4 +30,66 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
public class BalanceSheet extends SimpleEntity {
@ManyToOne
private Stock stock;
@Comment("年报年度")
private Integer year;
@Comment("原始名称total_share描述期末总股本")
private Double endingTotalShares;
@Comment("原始名称cap_rese描述资本公积金")
private Double capitalSurplus;
@Comment("原始名称undist_profit描述未分配利润")
private Double undistributedProfit;
@Comment("原始名称money_cap描述货币资金")
private Double monetaryFunds;
@Comment("原始名称accounts_receiv描述应收账款")
private Double accountsReceivable;
@Comment("原始名称inventories描述存货")
private Double inventories;
@Comment("原始名称total_cur_assets描述流动资产合计")
private Double totalCurrentAssets;
@Comment("原始名称lt_eqt_invest描述长期股权投资")
private Double longTermEquityInvestments;
@Comment("原始名称lt_rec描述长期应收款")
private Double longTermReceivables;
@Comment("原始名称fix_assets描述固定资产")
private Double fixedAssets;
@Comment("原始名称r_and_d描述研发支出")
private Double researchAndDevelopmentExpenditures;
@Comment("原始名称goodwill描述商誉")
private Double goodwill;
@Comment("原始名称total_nca描述非流动资产合计")
private Double totalNonCurrentAssets;
@Comment("原始名称total_assets描述资产总计")
private Double totalAssets;
@Comment("原始名称lt_borr描述长期借款")
private Double longTermBorrowings;
@Comment("原始名称st_borr描述短期借款")
private Double shortTermBorrowings;
@Comment("原始名称acct_payable描述应付账款")
private Double accountsPayable;
@Comment("原始名称adv_receipts描述预收款项")
private Double advancesReceived;
@Comment("原始名称total_cur_lab描述流动负债合计")
private Double totalCurrentLiabilities;
@Comment("原始名称total_ncl描述非流动负债合计")
private Double totalNonCurrentLiabilities;
@Comment("原始名称total_lab描述负债合计")
private Double totalLiabilities;
@Comment("原始名称total_hldr_eqy_exc_min_int描述股东权益合计(不含少数股东权益)")
private Double totalShareholdersEquityExcludingMinorityInterest;
@Comment("原始名称total_hldr_eqy_inc_min_int描述股东权益合计(含少数股东权益)")
private Double totalShareholdersEquityIncludingMinorityInterest;
@Comment("原始名称total_lab_hldr_eqy描述负债及股东权益总计")
private Double totalLiabilitiesAndShareholdersEquity;
@Comment("原始名称acc_receivable描述应收款项")
private Double receivables;
@Comment("原始名称payables描述应付款项")
private Double payables;
@Comment("原始名称accounts_receiv_bill描述应收票据及应收账款")
private Double notesAndAccountsReceivable;
@Comment("原始名称accounts_pay_bill描述应付票据及应付账款")
private Double notesAndAccountsPayable;
@Comment("原始名称oth_rcv_total描述其他应收款(合计)(元)")
private Double otherReceivablesTotal;
@Comment("原始名称fix_assets_total描述固定资产(合计)(元)")
private Double fixedAssetsTotal;
}

View File

@@ -10,6 +10,7 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
@@ -29,4 +30,32 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
public class CashFlow extends SimpleEntity {
@ManyToOne
private Stock stock;
@Comment("年报年度")
private Integer year;
@Comment("原始名称net_profit描述净利润")
private Double netProfit;
@Comment("原始名称fin_exp描述财务费用")
private Double financialExpense;
@Comment("原始名称c_f_sale_sg描述销售商品、提供劳务收到的现金")
private Double cashReceivedFromSalesAndServices;
@Comment("原始名称c_f_oth_oper_a描述经营活动现金流入小计")
private Double subtotalOfCashInflowsFromOperatingActivities;
@Comment("原始名称c_paid_to_for_empl描述支付给职工以及为职工支付的现金")
private Double cashPaidToAndForEmployees;
@Comment("原始名称c_paid_for_taxes描述支付的各项税费")
private Double cashPaidForVariousTaxes;
@Comment("原始名称st_cashflow_act描述经营活动产生的现金流量净额")
private Double netCashFlowFromOperatingActivities;
@Comment("原始名称stoc_inflows_inv_act描述投资活动现金流入小计")
private Double subtotalOfCashInflowsFromInvestingActivities;
@Comment("原始名称c_paid_subs_oth_biz描述购置固定资产、无形资产和其他长期资产支付的现金")
private Double cashPaidForAcquisitionOfFixedIntangibleAndOtherLongTermAssets;
@Comment("原始名称stoc_cashout_inv_act描述投资活动现金流出小计")
private Double subtotalOfCashOutflowsFromInvestingActivities;
@Comment("原始名称stoc_cashout_fin_act描述筹资活动现金流出小计")
private Double subtotalOfCashOutflowsFromFinancingActivities;
@Comment("原始名称c_cash_equ_beg_period描述期初现金及现金等价物余额")
private Double beginningBalanceOfCashAndCashEquivalents;
@Comment("原始名称c_cash_equ_end_period描述期末现金及现金等价物余额")
private Double endingBalanceOfCashAndCashEquivalents;
}

View File

@@ -10,6 +10,7 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
@@ -29,4 +30,60 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
public class Income extends SimpleEntity {
@ManyToOne
private Stock stock;
@Comment("年报年度")
private Integer year;
@Comment("原始名称basic_eps描述基本每股收益")
private Double basicEarningsPerShare;
@Comment("原始名称diluted_eps描述稀释每股收益")
private Double dilutedEarningsPerShare;
@Comment("原始名称total_revenue描述营业总收入")
private Double totalOperatingRevenue;
@Comment("原始名称revenue描述营业收入")
private Double operatingRevenue;
@Comment("原始名称total_cogs描述营业总成本")
private Double totalOperatingCost;
@Comment("原始名称oper_cost描述减:营业成本")
private Double operatingCost;
@Comment("原始名称sell_exp描述减:销售费用")
private Double sellingExpense;
@Comment("原始名称admin_exp描述减:管理费用")
private Double administrativeExpense;
@Comment("原始名称fin_exp描述减:财务费用")
private Double financialExpense;
@Comment("原始名称oper_exp描述营业支出")
private Double operatingExpense;
@Comment("原始名称operate_profit描述营业利润")
private Double operatingProfit;
@Comment("原始名称non_oper_income描述加:营业外收入")
private Double addNonOperatingIncome;
@Comment("原始名称non_oper_exp描述减:营业外支出")
private Double lessNonOperatingExpense;
@Comment("原始名称total_profit描述利润总额")
private Double totalProfit;
@Comment("原始名称income_tax描述所得税费用")
private Double incomeTaxExpense;
@Comment("原始名称n_income描述净利润(含少数股东损益)")
private Double netProfitIncludingMinorityInterest;
@Comment("原始名称n_income_attr_p描述净利润(不含少数股东损益)")
private Double netProfitExcludingMinorityInterest;
@Comment("原始名称compr_inc_attr_p描述归属于母公司(或股东)的综合收益总额")
private Double comprehensiveIncomeAttributableToParent;
@Comment("原始名称compr_inc_attr_m_s描述归属于少数股东的综合收益总额")
private Double comprehensiveIncomeAttributableToMinorityShareholders;
@Comment("原始名称ebit描述息税前利润")
private Double earningsBeforeInterestAndTax;
@Comment("原始名称ebida描述息税折旧摊销前利润")
private Double earningsBeforeInterestTaxDepreciationAndAmortization;
@Comment("原始名称undist_profit描述年初未分配利润")
private Double beginningUndistributedProfit;
@Comment("原始名称distable_profit描述可分配利润")
private Double distributableProfit;
@Comment("原始名称rd_exp描述研发费用")
private Double researchAndDevelopmentExpense;
@Comment("原始名称fin_exp_int_exp描述财务费用-利息费用")
private Double financialExpenseInterestExpense;
@Comment("原始名称continued_net_profit描述持续经营净利润")
private Double netProfitFromContinuingOperations;
@Comment("原始名称end_net_profit描述终止经营净利润")
private Double netProfitFromDiscontinuedOperations;
}

View File

@@ -9,7 +9,6 @@ import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.time.LocalDate;
@@ -74,10 +73,6 @@ public class Stock extends SimpleEntity {
@ToString.Exclude
private Set<CashFlow> cashFlows;
@ManyToMany
@ToString.Exclude
private Set<StockCollection> collections;
@Getter
@AllArgsConstructor
public enum Market implements SimpleEnum {

View File

@@ -34,4 +34,6 @@ public class TaskTemplate extends SimpleEntity {
private String chain;
@Column(nullable = false)
private String expression;
@Column(nullable = false)
private String expressionEl;
}

View File

@@ -0,0 +1,13 @@
package com.lanyuanxiaoyao.leopard.core.repository;
import com.lanyuanxiaoyao.leopard.core.entity.BalanceSheet;
import com.lanyuanxiaoyao.service.template.repository.SimpleRepository;
import org.springframework.stereotype.Repository;
/**
* @author lanyuanxiaoyao
* @version 20250911
*/
@Repository
public interface BalanceSheetRepository extends SimpleRepository<BalanceSheet> {
}

View File

@@ -0,0 +1,13 @@
package com.lanyuanxiaoyao.leopard.core.repository;
import com.lanyuanxiaoyao.leopard.core.entity.CashFlow;
import com.lanyuanxiaoyao.service.template.repository.SimpleRepository;
import org.springframework.stereotype.Repository;
/**
* @author lanyuanxiaoyao
* @version 20250911
*/
@Repository
public interface CashFlowRepository extends SimpleRepository<CashFlow> {
}

View File

@@ -0,0 +1,13 @@
package com.lanyuanxiaoyao.leopard.core.repository;
import com.lanyuanxiaoyao.leopard.core.entity.Income;
import com.lanyuanxiaoyao.service.template.repository.SimpleRepository;
import org.springframework.stereotype.Repository;
/**
* @author lanyuanxiaoyao
* @version 20250911
*/
@Repository
public interface IncomeRepository extends SimpleRepository<Income> {
}

View File

@@ -0,0 +1,25 @@
package com.lanyuanxiaoyao.leopard.core;
import com.lanyuanxiaoyao.service.template.util.DDLGenerator;
import org.hibernate.dialect.PostgreSQLDialect;
import org.postgresql.Driver;
/**
* 建表语句
*
* @author lanyuanxiaoyao
* @version 20250911
*/
public class GenerateDDL {
public static void main(String[] args) {
DDLGenerator.generateDDL(
"com.lanyuanxiaoyao.leopard.core.entity",
"/Users/lanyuanxiaoyao/Project/IdeaProjects/leopard/leopard-core/target",
PostgreSQLDialect.class,
"jdbc:postgresql://81.71.3.24:6785/leopard_dev",
"leopard",
"9NEzFzovnddf@PyEP?e*AYAWnCyd7UhYwQK$pJf>7?ccFiN^x4$eKEZ5~E<7<+~X",
Driver.class
);
}
}

View File

@@ -1,6 +1,7 @@
package com.lanyuanxiaoyao.leopard.server.controller;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.leopard.core.entity.TaskTemplate;
import com.lanyuanxiaoyao.leopard.server.service.TaskTemplateService;
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
@@ -31,6 +32,7 @@ public class TaskTemplateController extends SimpleControllerSupport<TaskTemplate
template.setApplication(application);
template.setChain(IdUtil.simpleUUID());
template.setExpression(item.expression());
template.setExpressionEl(StrUtil.format("CATCH(THEN(task_start, ({}), task_end)).DO(task_error)", item.expression()));
return template;
};
}

View File

@@ -3,6 +3,7 @@ package com.lanyuanxiaoyao.leopard.server.service;
import com.lanyuanxiaoyao.leopard.core.entity.TaskTemplate;
import com.lanyuanxiaoyao.leopard.core.repository.TaskTemplateRepository;
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
import com.yomahub.liteflow.meta.LiteflowMetaOperator;
import org.springframework.stereotype.Service;
@@ -12,8 +13,16 @@ public class TaskTemplateService extends SimpleServiceSupport<TaskTemplate> {
super(repository);
}
private void validateExpression(String expression) {
var response = LiteFlowChainELBuilder.validateWithEx(expression);
if (!response.isSuccess()) {
throw new RuntimeException(response.getCause());
}
}
@Override
public Long save(TaskTemplate entity) {
validateExpression(entity.getExpression());
Long id = super.save(entity);
LiteflowMetaOperator.reloadAllChain();
return id;
@@ -21,6 +30,7 @@ public class TaskTemplateService extends SimpleServiceSupport<TaskTemplate> {
@Override
public void save(Iterable<TaskTemplate> taskTemplates) {
taskTemplates.forEach(template -> validateExpression(template.getExpression()));
super.save(taskTemplates);
LiteflowMetaOperator.reloadAllChain();
}

View File

@@ -23,10 +23,9 @@ import org.springframework.stereotype.Service;
@Slf4j
@Service
public class TuShareService {
public static final DateTimeFormatter TRADE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
private static final String API_URL = "https://api.tushare.pro";
private static final String API_TOKEN = "64ebff4fa679167600b905ee45dd88e76f3963c0ff39157f3f085f0e";
public static final DateTimeFormatter TRADE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
private final ObjectMapper mapper;
public TuShareService(Jackson2ObjectMapperBuilder builder) {
@@ -108,6 +107,124 @@ public class TuShareService {
return tuShareResponse;
}
@SneakyThrows
public TuShareResponse incomeList(int year) {
var response = HttpUtil.post(API_URL, buildRequest(
"income_vip",
Map.of("period", LocalDate.of(year, 12, 31).format(TRADE_FORMAT)),
List.of(
"ts_code",
"basic_eps",
"diluted_eps",
"total_revenue",
"revenue",
"total_cogs",
"oper_cost",
"sell_exp",
"admin_exp",
"fin_exp",
"oper_exp",
"operate_profit",
"non_oper_income",
"non_oper_exp",
"total_profit",
"income_tax",
"n_income",
"n_income_attr_p",
"compr_inc_attr_p",
"compr_inc_attr_m_s",
"ebit",
"ebida",
"undist_profit",
"distable_profit",
"rd_exp",
"fin_exp_int_exp",
"continued_net_profit",
"end_net_profit"
)
));
var tuShareResponse = mapper.readValue(response, TuShareResponse.class);
if (tuShareResponse.code != 0) {
throw new RuntimeException(tuShareResponse.message);
}
return tuShareResponse;
}
@SneakyThrows
public TuShareResponse balanceList(int year) {
var response = HttpUtil.post(API_URL, buildRequest(
"balancesheet_vip",
Map.of("period", LocalDate.of(year, 12, 31).format(TRADE_FORMAT)),
List.of(
"ts_code",
"total_share",
"cap_rese",
"undist_profit",
"money_cap",
"accounts_receiv",
"inventories",
"total_cur_assets",
"lt_eqt_invest",
"lt_rec",
"fix_assets",
"r_and_d",
"goodwill",
"total_nca",
"total_assets",
"lt_borr",
"st_borr",
"acct_payable",
"adv_receipts",
"total_cur_lab",
"total_ncl",
"total_lab",
"total_hldr_eqy_exc_min_int",
"total_hldr_eqy_inc_min_int",
"total_lab_hldr_eqy",
"acc_receivable",
"payables",
"accounts_receiv_bill",
"accounts_pay_bill",
"oth_rcv_total",
"fix_assets_total"
)
));
var tuShareResponse = mapper.readValue(response, TuShareResponse.class);
if (tuShareResponse.code != 0) {
throw new RuntimeException(tuShareResponse.message);
}
return tuShareResponse;
}
@SneakyThrows
public TuShareResponse cashFlowList(int year) {
var response = HttpUtil.post(API_URL, buildRequest(
"cashflow_vip",
Map.of("period", LocalDate.of(year, 12, 31).format(TRADE_FORMAT)),
List.of(
"ts_code",
"net_profit",
"fin_exp",
"c_f_sale_sg",
"c_f_oth_oper_a",
"c_paid_to_for_empl",
"c_paid_for_taxes",
"st_cashflow_act",
"stoc_inflows_inv_act",
"c_paid_subs_oth_biz",
"stoc_cashout_inv_act",
"stoc_cashout_fin_act",
"c_cash_equ_beg_period",
"c_cash_equ_end_period"
)
));
var tuShareResponse = mapper.readValue(response, TuShareResponse.class);
if (tuShareResponse.code != 0) {
throw new RuntimeException(tuShareResponse.message);
}
return tuShareResponse;
}
public record TuShareResponse(
Integer code,
@JsonProperty("msg")

View File

@@ -0,0 +1,162 @@
package com.lanyuanxiaoyao.leopard.server.service.task;
import com.lanyuanxiaoyao.leopard.core.entity.BalanceSheet;
import com.lanyuanxiaoyao.leopard.core.entity.CashFlow;
import com.lanyuanxiaoyao.leopard.core.entity.Income;
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.core.repository.BalanceSheetRepository;
import com.lanyuanxiaoyao.leopard.core.repository.CashFlowRepository;
import com.lanyuanxiaoyao.leopard.core.repository.IncomeRepository;
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
/**
* 更新财务数据
*
* @author lanyuanxiaoyao
* @version 20250911
*/
@Slf4j
@LiteflowComponent("update_finance")
public class UpdateFinanceNode extends TaskNodeComponent {
private final TuShareService tuShareService;
private final StockRepository stockRepository;
private final IncomeRepository incomeRepository;
private final BalanceSheetRepository balanceSheetRepository;
private final CashFlowRepository cashFlowRepository;
public UpdateFinanceNode(TaskService taskService, TuShareService tuShareService, StockRepository stockRepository, IncomeRepository incomeRepository, BalanceSheetRepository balanceSheetRepository, CashFlowRepository cashFlowRepository) {
super(taskService);
this.tuShareService = tuShareService;
this.stockRepository = stockRepository;
this.incomeRepository = incomeRepository;
this.balanceSheetRepository = balanceSheetRepository;
this.cashFlowRepository = cashFlowRepository;
}
@Override
public void process() {
var stocks = stockRepository.findAll();
var stocksMap = stocks.stream().collect(Collectors.toMap(Stock::getCode, stock -> stock));
var currentYear = LocalDate.now().getYear();
for (int year = 1990; year < currentYear; year++) {
var response = tuShareService.incomeList(year);
for (List<String> item : response.data().items()) {
var code = item.get(0);
if (!stocksMap.containsKey(code)) {
continue;
}
var stock = stocksMap.get(code);
var income = new Income();
income.setStock(stock);
income.setYear(year);
income.setBasicEarningsPerShare(Double.parseDouble(item.get(1)));
income.setDilutedEarningsPerShare(Double.parseDouble(item.get(2)));
income.setTotalOperatingRevenue(Double.parseDouble(item.get(3)));
income.setOperatingRevenue(Double.parseDouble(item.get(4)));
income.setTotalOperatingCost(Double.parseDouble(item.get(5)));
income.setOperatingCost(Double.parseDouble(item.get(6)));
income.setSellingExpense(Double.parseDouble(item.get(7)));
income.setAdministrativeExpense(Double.parseDouble(item.get(8)));
income.setFinancialExpense(Double.parseDouble(item.get(9)));
income.setOperatingExpense(Double.parseDouble(item.get(10)));
income.setOperatingProfit(Double.parseDouble(item.get(11)));
income.setAddNonOperatingIncome(Double.parseDouble(item.get(12)));
income.setLessNonOperatingExpense(Double.parseDouble(item.get(13)));
income.setTotalProfit(Double.parseDouble(item.get(14)));
income.setIncomeTaxExpense(Double.parseDouble(item.get(15)));
income.setNetProfitIncludingMinorityInterest(Double.parseDouble(item.get(16)));
income.setNetProfitExcludingMinorityInterest(Double.parseDouble(item.get(17)));
income.setComprehensiveIncomeAttributableToParent(Double.parseDouble(item.get(18)));
income.setComprehensiveIncomeAttributableToMinorityShareholders(Double.parseDouble(item.get(19)));
income.setEarningsBeforeInterestAndTax(Double.parseDouble(item.get(20)));
income.setEarningsBeforeInterestTaxDepreciationAndAmortization(Double.parseDouble(item.get(21)));
income.setBeginningUndistributedProfit(Double.parseDouble(item.get(22)));
income.setDistributableProfit(Double.parseDouble(item.get(23)));
income.setResearchAndDevelopmentExpense(Double.parseDouble(item.get(24)));
income.setFinancialExpenseInterestExpense(Double.parseDouble(item.get(25)));
income.setNetProfitFromContinuingOperations(Double.parseDouble(item.get(26)));
income.setNetProfitFromDiscontinuedOperations(Double.parseDouble(item.get(27)));
incomeRepository.save(income);
}
response = tuShareService.balanceList(year);
for (List<String> item : response.data().items()) {
var code = item.get(0);
if (!stocksMap.containsKey(code)) {
continue;
}
var stock = stocksMap.get(code);
var balanceSheet = new BalanceSheet();
balanceSheet.setStock(stock);
balanceSheet.setYear(year);
balanceSheet.setEndingTotalShares(Double.parseDouble(item.get(1)));
balanceSheet.setCapitalSurplus(Double.parseDouble(item.get(2)));
balanceSheet.setUndistributedProfit(Double.parseDouble(item.get(3)));
balanceSheet.setMonetaryFunds(Double.parseDouble(item.get(4)));
balanceSheet.setAccountsReceivable(Double.parseDouble(item.get(5)));
balanceSheet.setInventories(Double.parseDouble(item.get(6)));
balanceSheet.setTotalCurrentAssets(Double.parseDouble(item.get(7)));
balanceSheet.setLongTermEquityInvestments(Double.parseDouble(item.get(8)));
balanceSheet.setLongTermReceivables(Double.parseDouble(item.get(9)));
balanceSheet.setFixedAssets(Double.parseDouble(item.get(10)));
balanceSheet.setResearchAndDevelopmentExpenditures(Double.parseDouble(item.get(11)));
balanceSheet.setGoodwill(Double.parseDouble(item.get(12)));
balanceSheet.setTotalNonCurrentAssets(Double.parseDouble(item.get(13)));
balanceSheet.setTotalAssets(Double.parseDouble(item.get(14)));
balanceSheet.setLongTermBorrowings(Double.parseDouble(item.get(15)));
balanceSheet.setShortTermBorrowings(Double.parseDouble(item.get(16)));
balanceSheet.setAccountsPayable(Double.parseDouble(item.get(17)));
balanceSheet.setAdvancesReceived(Double.parseDouble(item.get(18)));
balanceSheet.setTotalCurrentLiabilities(Double.parseDouble(item.get(19)));
balanceSheet.setTotalNonCurrentLiabilities(Double.parseDouble(item.get(20)));
balanceSheet.setTotalLiabilities(Double.parseDouble(item.get(21)));
balanceSheet.setTotalShareholdersEquityExcludingMinorityInterest(Double.parseDouble(item.get(22)));
balanceSheet.setTotalShareholdersEquityIncludingMinorityInterest(Double.parseDouble(item.get(23)));
balanceSheet.setTotalLiabilitiesAndShareholdersEquity(Double.parseDouble(item.get(24)));
balanceSheet.setAccountsReceivable(Double.parseDouble(item.get(25)));
balanceSheet.setPayables(Double.parseDouble(item.get(26)));
balanceSheet.setNotesAndAccountsReceivable(Double.parseDouble(item.get(27)));
balanceSheet.setNotesAndAccountsPayable(Double.parseDouble(item.get(28)));
balanceSheet.setOtherReceivablesTotal(Double.parseDouble(item.get(29)));
balanceSheet.setFixedAssetsTotal(Double.parseDouble(item.get(30)));
balanceSheetRepository.save(balanceSheet);
}
response = tuShareService.cashFlowList(year);
for (List<String> item : response.data().items()) {
var code = item.get(0);
if (!stocksMap.containsKey(code)) {
continue;
}
var stock = stocksMap.get(code);
var cashFlow = new CashFlow();
cashFlow.setStock(stock);
cashFlow.setYear(year);
cashFlow.setNetProfit(Double.parseDouble(item.get(1)));
cashFlow.setFinancialExpense(Double.parseDouble(item.get(2)));
cashFlow.setCashReceivedFromSalesAndServices(Double.parseDouble(item.get(3)));
cashFlow.setSubtotalOfCashInflowsFromOperatingActivities(Double.parseDouble(item.get(4)));
cashFlow.setCashPaidToAndForEmployees(Double.parseDouble(item.get(5)));
cashFlow.setCashPaidForVariousTaxes(Double.parseDouble(item.get(6)));
cashFlow.setNetCashFlowFromOperatingActivities(Double.parseDouble(item.get(7)));
cashFlow.setSubtotalOfCashInflowsFromInvestingActivities(Double.parseDouble(item.get(8)));
cashFlow.setCashPaidForAcquisitionOfFixedIntangibleAndOtherLongTermAssets(Double.parseDouble(item.get(9)));
cashFlow.setSubtotalOfCashOutflowsFromInvestingActivities(Double.parseDouble(item.get(10)));
cashFlow.setSubtotalOfCashOutflowsFromFinancingActivities(Double.parseDouble(item.get(11)));
cashFlow.setBeginningBalanceOfCashAndCashEquivalents(Double.parseDouble(item.get(12)));
cashFlowRepository.save(cashFlow);
}
setStep((year - 1990) * 100 / (currentYear - 1990));
}
}
}

View File

@@ -44,4 +44,4 @@ liteflow:
chainTableName: leopard_task_template
chainApplicationNameField: application
chainNameField: chain
elDataField: expression
elDataField: expression_el

View File

@@ -28,7 +28,7 @@
</appender>
<logger name="com.zaxxer.hikari" level="ERROR"/>
<logger name="org.hibernate.SQL" level="DEBUG"/>
<!--<logger name="org.hibernate.SQL" level="DEBUG"/>-->
<root level="INFO">
<appender-ref ref="Console"/>

View File

@@ -29,24 +29,39 @@ POST {{api_url}}
Content-Type: application/json
{
"api_name": "income",
"api_name": "income_vip",
"token": "{{api_key}}",
"params": {
"ts_code": "600000.SH"
"period": "20241231"
},
"fields": [
"ts_code",
"ann_date",
"fiscal_year",
"report_type",
"net_profit",
"basic_eps",
"diluted_eps",
"total_revenue",
"total_cost",
"gross_profit",
"operating_profit",
"net_profit_before_tax",
"net_profit_to_parent",
"total_revenue_to_parent"
"revenue",
"total_cogs",
"oper_cost",
"sell_exp",
"admin_exp",
"fin_exp",
"oper_exp",
"operate_profit",
"non_oper_income",
"non_oper_exp",
"total_profit",
"income_tax",
"n_income",
"n_income_attr_p",
"compr_inc_attr_p",
"compr_inc_attr_m_s",
"ebit",
"ebida",
"undist_profit",
"distable_profit",
"rd_exp",
"fin_exp_int_exp",
"continued_net_profit",
"end_net_profit"
]
}

View File

@@ -122,7 +122,7 @@ function StockList() {
{
name: 'industry',
label: '行业',
width: 150,
width: 80,
},
{
label: '上市日期',

1212
note.md

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,7 @@
<spring-boot.version>3.5.0</spring-boot.version>
<spring-cloud.version>2025.0.0</spring-cloud.version>
<spring-ai.version>1.0.1</spring-ai.version>
<hibernate.version>6.6.15.Final</hibernate.version>
<eclipse-collections.version>13.0.0</eclipse-collections.version>
<hutool.version>5.8.39</hutool.version>
@@ -74,6 +75,12 @@
<version>${liteflow.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-ant</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>