refactor: 后端架构优化 P0-P1
P0: 移除硬编码 API Key - MarketDataService Tiingo Key 改为强制环境变量 P1: 拆分 Entity 文件 - 从 Portfolio.cs 提取 Position.cs - 从 Portfolio.cs 提取 Transaction.cs - 每个实体独立文件,符合单一职责原则
This commit is contained in:
parent
34f06ce941
commit
abcdc7110b
@ -68,161 +68,3 @@ public class Portfolio
|
||||
[SugarColumn(ColumnName = "updated_at")]
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 持仓明细表
|
||||
/// </summary>
|
||||
[SugarTable("positions")]
|
||||
public class Position
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属组合ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "portfolio_id", IndexGroupNameList = new string[] { "idx_portfolio_id" })]
|
||||
public string? PortfolioId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的代码 (如: UPRO.US)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "stock_code", Length = 50)]
|
||||
public string? StockCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "stock_name", Length = 200)]
|
||||
public string? StockName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 资产类型 (Stock/Crypto)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "asset_type", Length = 20)]
|
||||
public string? AssetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 持有数量
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "shares", ColumnDataType = "decimal(18,8)")]
|
||||
public decimal Shares { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 持仓均价
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "avg_price", ColumnDataType = "decimal(18,4)")]
|
||||
public decimal AvgPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的币种
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "currency", Length = 10)]
|
||||
public string? Currency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 建仓时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后更新时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "updated_at")]
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 交易流水表
|
||||
/// </summary>
|
||||
[SugarTable("transactions")]
|
||||
public class Transaction
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属组合ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "portfolio_id", IndexGroupNameList = new string[] { "idx_portfolio_id" })]
|
||||
public string? PortfolioId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易类型 (buy/sell)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "type", Length = 20)]
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的代码
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "stock_code", Length = 50)]
|
||||
public string? StockCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 资产类型 (Stock/Crypto)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "asset_type", Length = 20)]
|
||||
public string? AssetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易标题 (如: 定期定投)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "title", Length = 200)]
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易数量
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "amount", ColumnDataType = "decimal(18,8)")]
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 成交价格
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "price", ColumnDataType = "decimal(18,4)")]
|
||||
public decimal Price { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易总金额
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "total_amount", ColumnDataType = "decimal(18,4)")]
|
||||
public decimal TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易币种
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "currency", Length = 10)]
|
||||
public string? Currency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易状态 (processing/completed)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "status", Length = 50)]
|
||||
public string? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易备注
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "remark", Length = 500, IsNullable = true)]
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易发生时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "transaction_time")]
|
||||
public DateTime TransactionTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 记录创建时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
70
AssetManager.Data/Position.cs
Normal file
70
AssetManager.Data/Position.cs
Normal file
@ -0,0 +1,70 @@
|
||||
using SqlSugar;
|
||||
|
||||
namespace AssetManager.Data;
|
||||
|
||||
/// <summary>
|
||||
/// 持仓明细表
|
||||
/// </summary>
|
||||
[SugarTable("positions")]
|
||||
public class Position
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属组合ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "portfolio_id", IndexGroupNameList = new string[] { "idx_portfolio_id" })]
|
||||
public string? PortfolioId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的代码 (如: UPRO.US)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "stock_code", Length = 50)]
|
||||
public string? StockCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "stock_name", Length = 200)]
|
||||
public string? StockName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 资产类型 (Stock/Crypto)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "asset_type", Length = 20)]
|
||||
public string? AssetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 持有数量
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "shares", ColumnDataType = "decimal(18,8)")]
|
||||
public decimal Shares { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 持仓均价
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "avg_price", ColumnDataType = "decimal(18,4)")]
|
||||
public decimal AvgPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的币种
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "currency", Length = 10)]
|
||||
public string? Currency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 建仓时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后更新时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "updated_at")]
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
}
|
||||
94
AssetManager.Data/Transaction.cs
Normal file
94
AssetManager.Data/Transaction.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using SqlSugar;
|
||||
|
||||
namespace AssetManager.Data;
|
||||
|
||||
/// <summary>
|
||||
/// 交易流水表
|
||||
/// </summary>
|
||||
[SugarTable("transactions")]
|
||||
public class Transaction
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键
|
||||
/// </summary>
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属组合ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "portfolio_id", IndexGroupNameList = new string[] { "idx_portfolio_id" })]
|
||||
public string? PortfolioId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易类型 (buy/sell)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "type", Length = 20)]
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的代码
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "stock_code", Length = 50)]
|
||||
public string? StockCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 资产类型 (Stock/Crypto)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "asset_type", Length = 20)]
|
||||
public string? AssetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易标题 (如: 定期定投)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "title", Length = 200)]
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易数量
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "amount", ColumnDataType = "decimal(18,8)")]
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 成交价格
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "price", ColumnDataType = "decimal(18,4)")]
|
||||
public decimal Price { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易总金额
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "total_amount", ColumnDataType = "decimal(18,4)")]
|
||||
public decimal TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易币种
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "currency", Length = 10)]
|
||||
public string? Currency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易状态 (processing/completed)
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "status", Length = 50)]
|
||||
public string? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易备注
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "remark", Length = 500, IsNullable = true)]
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易发生时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "transaction_time")]
|
||||
public DateTime TransactionTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 记录创建时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
@ -33,10 +33,12 @@ public class MarketDataService : IMarketDataService
|
||||
_logger = logger;
|
||||
_httpClient = httpClientFactory.CreateClient();
|
||||
_databaseService = databaseService;
|
||||
// 完全从环境变量读取 Tiingo API Key
|
||||
|
||||
// 从环境变量读取 Tiingo API Key(必填)
|
||||
_tiingoApiKey = Environment.GetEnvironmentVariable("Tiingo__ApiKey")
|
||||
?? Environment.GetEnvironmentVariable("TIINGO_API_KEY")
|
||||
?? "bd00fee76d3012b047473078904001b33322cb46";
|
||||
?? throw new InvalidOperationException("Tiingo__ApiKey 环境变量未配置");
|
||||
|
||||
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Token {_tiingoApiKey}");
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user