refactor: 将模型属性改为可为空类型以增强健壮性
- 修改ApiResponse、RiskParityConfig等DTO类的属性为可空类型 - 在策略计算器中添加空值检查逻辑 - 更新服务层代码处理可能的空值情况 - 添加发布配置文件FolderProfile.pubxml
This commit is contained in:
parent
c994a5bb76
commit
b5499ef7fe
@ -44,6 +44,15 @@ public class AuthController : ControllerBase
|
|||||||
_logger.LogInformation("Wechat login attempt");
|
_logger.LogInformation("Wechat login attempt");
|
||||||
|
|
||||||
// 用code换取openid
|
// 用code换取openid
|
||||||
|
if (request.Code == null)
|
||||||
|
{
|
||||||
|
return BadRequest(new ApiResponse<WechatLoginResponse>
|
||||||
|
{
|
||||||
|
code = AssetManager.Models.StatusCodes.BadRequest,
|
||||||
|
data = null,
|
||||||
|
message = "Code is required"
|
||||||
|
});
|
||||||
|
}
|
||||||
var authResult = await _wechatService.GetOpenIdAsync(request.Code);
|
var authResult = await _wechatService.GetOpenIdAsync(request.Code);
|
||||||
|
|
||||||
if (authResult.Errcode != 0)
|
if (authResult.Errcode != 0)
|
||||||
@ -93,7 +102,7 @@ public class AuthController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 生成真实的JWT令牌
|
// 生成真实的JWT令牌
|
||||||
var token = _jwtService.GenerateToken(user.Id, user.UserName, user.Email);
|
var token = _jwtService.GenerateToken(user.Id ?? "", user.UserName ?? "", user.Email ?? "");
|
||||||
|
|
||||||
var response = new WechatLoginResponse
|
var response = new WechatLoginResponse
|
||||||
{
|
{
|
||||||
|
|||||||
@ -41,7 +41,7 @@ public class PortfolioController : ControllerBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private string GetCurrentUserId()
|
private string GetCurrentUserId()
|
||||||
{
|
{
|
||||||
return User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
return User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? throw new Exception("User not authenticated");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -433,6 +433,15 @@ public class PortfolioController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. 获取策略
|
// 2. 获取策略
|
||||||
|
if (portfolio.StrategyId == null)
|
||||||
|
{
|
||||||
|
return NotFound(new ApiResponse<StrategySignal>
|
||||||
|
{
|
||||||
|
code = AssetManager.Models.StatusCodes.NotFound,
|
||||||
|
data = null,
|
||||||
|
message = "策略ID不存在"
|
||||||
|
});
|
||||||
|
}
|
||||||
var strategy = _strategyService.GetStrategyById(portfolio.StrategyId, userId);
|
var strategy = _strategyService.GetStrategyById(portfolio.StrategyId, userId);
|
||||||
if (strategy == null)
|
if (strategy == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<DeleteExistingFiles>false</DeleteExistingFiles>
|
||||||
|
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||||
|
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||||
|
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||||
|
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||||
|
<PublishProvider>FileSystem</PublishProvider>
|
||||||
|
<PublishUrl>bin\Release\net8.0\publish\</PublishUrl>
|
||||||
|
<WebPublishMethod>FileSystem</WebPublishMethod>
|
||||||
|
<_TargetId>Folder</_TargetId>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@ -12,31 +12,31 @@ public class Portfolio
|
|||||||
/// 主键
|
/// 主键
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
||||||
public string Id { get; set; }
|
public string? Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所属用户ID
|
/// 所属用户ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "user_id", IndexGroupNameList = new string[] { "idx_user_id" })]
|
[SugarColumn(ColumnName = "user_id", IndexGroupNameList = new string[] { "idx_user_id" })]
|
||||||
public string UserId { get; set; }
|
public string? UserId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所用策略ID
|
/// 所用策略ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "strategy_id", IndexGroupNameList = new string[] { "idx_strategy_id" })]
|
[SugarColumn(ColumnName = "strategy_id", IndexGroupNameList = new string[] { "idx_strategy_id" })]
|
||||||
public string StrategyId { get; set; }
|
public string? StrategyId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 组合名称
|
/// 组合名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "name", Length = 200)]
|
[SugarColumn(ColumnName = "name", Length = 200)]
|
||||||
public string Name { get; set; }
|
public string? Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 组合币种 (USD/CNY等)
|
/// 组合币种 (USD/CNY等)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "currency", Length = 10)]
|
[SugarColumn(ColumnName = "currency", Length = 10)]
|
||||||
public string Currency { get; set; }
|
public string? Currency { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前总市值 (可冗余或实时计算)
|
/// 当前总市值 (可冗余或实时计算)
|
||||||
@ -54,7 +54,7 @@ public class Portfolio
|
|||||||
/// 运行状态 (运行中/监控中)
|
/// 运行状态 (运行中/监控中)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "status", Length = 50)]
|
[SugarColumn(ColumnName = "status", Length = 50)]
|
||||||
public string Status { get; set; }
|
public string? Status { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建时间
|
/// 创建时间
|
||||||
@ -79,31 +79,31 @@ public class Position
|
|||||||
/// 主键
|
/// 主键
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
||||||
public string Id { get; set; }
|
public string? Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所属组合ID
|
/// 所属组合ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "portfolio_id", IndexGroupNameList = new string[] { "idx_portfolio_id" })]
|
[SugarColumn(ColumnName = "portfolio_id", IndexGroupNameList = new string[] { "idx_portfolio_id" })]
|
||||||
public string PortfolioId { get; set; }
|
public string? PortfolioId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标的代码 (如: UPRO.US)
|
/// 标的代码 (如: UPRO.US)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "stock_code", Length = 50)]
|
[SugarColumn(ColumnName = "stock_code", Length = 50)]
|
||||||
public string StockCode { get; set; }
|
public string? StockCode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标的名称
|
/// 标的名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "stock_name", Length = 200)]
|
[SugarColumn(ColumnName = "stock_name", Length = 200)]
|
||||||
public string StockName { get; set; }
|
public string? StockName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 资产类型 (Stock/Crypto)
|
/// 资产类型 (Stock/Crypto)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "asset_type", Length = 20)]
|
[SugarColumn(ColumnName = "asset_type", Length = 20)]
|
||||||
public string AssetType { get; set; }
|
public string? AssetType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 持有数量
|
/// 持有数量
|
||||||
@ -121,7 +121,7 @@ public class Position
|
|||||||
/// 标的币种
|
/// 标的币种
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "currency", Length = 10)]
|
[SugarColumn(ColumnName = "currency", Length = 10)]
|
||||||
public string Currency { get; set; }
|
public string? Currency { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 建仓时间
|
/// 建仓时间
|
||||||
@ -146,37 +146,37 @@ public class Transaction
|
|||||||
/// 主键
|
/// 主键
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
||||||
public string Id { get; set; }
|
public string? Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所属组合ID
|
/// 所属组合ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "portfolio_id", IndexGroupNameList = new string[] { "idx_portfolio_id" })]
|
[SugarColumn(ColumnName = "portfolio_id", IndexGroupNameList = new string[] { "idx_portfolio_id" })]
|
||||||
public string PortfolioId { get; set; }
|
public string? PortfolioId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 交易类型 (buy/sell)
|
/// 交易类型 (buy/sell)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "type", Length = 20)]
|
[SugarColumn(ColumnName = "type", Length = 20)]
|
||||||
public string Type { get; set; }
|
public string? Type { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标的代码
|
/// 标的代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "stock_code", Length = 50)]
|
[SugarColumn(ColumnName = "stock_code", Length = 50)]
|
||||||
public string StockCode { get; set; }
|
public string? StockCode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 资产类型 (Stock/Crypto)
|
/// 资产类型 (Stock/Crypto)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "asset_type", Length = 20)]
|
[SugarColumn(ColumnName = "asset_type", Length = 20)]
|
||||||
public string AssetType { get; set; }
|
public string? AssetType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 交易标题 (如: 定期定投)
|
/// 交易标题 (如: 定期定投)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "title", Length = 200)]
|
[SugarColumn(ColumnName = "title", Length = 200)]
|
||||||
public string Title { get; set; }
|
public string? Title { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 交易数量
|
/// 交易数量
|
||||||
@ -200,19 +200,19 @@ public class Transaction
|
|||||||
/// 交易币种
|
/// 交易币种
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "currency", Length = 10)]
|
[SugarColumn(ColumnName = "currency", Length = 10)]
|
||||||
public string Currency { get; set; }
|
public string? Currency { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 交易状态 (processing/completed)
|
/// 交易状态 (processing/completed)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "status", Length = 50)]
|
[SugarColumn(ColumnName = "status", Length = 50)]
|
||||||
public string Status { get; set; }
|
public string? Status { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 交易备注
|
/// 交易备注
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "remark", Length = 500, IsNullable = true)]
|
[SugarColumn(ColumnName = "remark", Length = 500, IsNullable = true)]
|
||||||
public string Remark { get; set; }
|
public string? Remark { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 交易发生时间
|
/// 交易发生时间
|
||||||
|
|||||||
@ -12,49 +12,49 @@ public class Strategy
|
|||||||
/// 主键
|
/// 主键
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
||||||
public string Id { get; set; }
|
public string? Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所属用户ID
|
/// 所属用户ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "user_id", Length = 100, IndexGroupNameList = new string[] { "idx_user_id" })]
|
[SugarColumn(ColumnName = "user_id", Length = 100, IndexGroupNameList = new string[] { "idx_user_id" })]
|
||||||
public string UserId { get; set; }
|
public string? UserId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 策略别名/名称
|
/// 策略别名/名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "alias", Length = 200)]
|
[SugarColumn(ColumnName = "alias", Length = 200)]
|
||||||
public string Alias { get; set; }
|
public string? Alias { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 策略类型 (如: ma_trend, chandelier_exit, risk_parity)
|
/// 策略类型 (如: ma_trend, chandelier_exit, risk_parity)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "type", Length = 50)]
|
[SugarColumn(ColumnName = "type", Length = 50)]
|
||||||
public string Type { get; set; }
|
public string? Type { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 策略描述
|
/// 策略描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "description", Length = 500)]
|
[SugarColumn(ColumnName = "description", Length = 500)]
|
||||||
public string Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 策略标签 (逗号分隔的字符串)
|
/// 策略标签 (逗号分隔的字符串)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "tags")]
|
[SugarColumn(ColumnName = "tags")]
|
||||||
public string Tags { get; set; }
|
public string? Tags { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 风险等级
|
/// 风险等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "risk_level", Length = 20)]
|
[SugarColumn(ColumnName = "risk_level", Length = 20)]
|
||||||
public string RiskLevel { get; set; }
|
public string? RiskLevel { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 策略配置项(周期,阈值,资产配比)
|
/// 策略配置项(周期,阈值,资产配比)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "config", IsJson = true)]
|
[SugarColumn(ColumnName = "config", IsJson = true)]
|
||||||
public string Config { get; set; }
|
public string? Config { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建时间
|
/// 创建时间
|
||||||
|
|||||||
@ -12,37 +12,37 @@ public class User
|
|||||||
/// 主键
|
/// 主键
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
[SugarColumn(IsPrimaryKey = true, IsIdentity = false)]
|
||||||
public string Id { get; set; }
|
public string? Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 微信OpenID (UK)
|
/// 微信OpenID (UK)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "open_id", Length = 100, IsNullable = true)]
|
[SugarColumn(ColumnName = "open_id", Length = 100, IsNullable = true)]
|
||||||
public string OpenId { get; set; }
|
public string? OpenId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户名
|
/// 用户名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "user_name", Length = 100)]
|
[SugarColumn(ColumnName = "user_name", Length = 100)]
|
||||||
public string UserName { get; set; }
|
public string? UserName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 邮箱
|
/// 邮箱
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "email", Length = 255, IsNullable = true)]
|
[SugarColumn(ColumnName = "email", Length = 255, IsNullable = true)]
|
||||||
public string Email { get; set; }
|
public string? Email { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 头像URL
|
/// 头像URL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "avatar", Length = 500, IsNullable = true)]
|
[SugarColumn(ColumnName = "avatar", Length = 500, IsNullable = true)]
|
||||||
public string Avatar { get; set; }
|
public string? Avatar { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 会员等级
|
/// 会员等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(ColumnName = "member_level", Length = 50)]
|
[SugarColumn(ColumnName = "member_level", Length = 50)]
|
||||||
public string MemberLevel { get; set; }
|
public string? MemberLevel { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户默认本位币 (CNY/USD/HKD)
|
/// 用户默认本位币 (CNY/USD/HKD)
|
||||||
|
|||||||
@ -55,6 +55,11 @@ public class ChandelierExitCalculator : IStrategyCalculator
|
|||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (position.StockCode == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 获取历史 K 线数据(需要 period + 1 根来计算 ATR)
|
// 获取历史 K 线数据(需要 period + 1 根来计算 ATR)
|
||||||
|
|||||||
@ -55,6 +55,11 @@ public class MaTrendCalculator : IStrategyCalculator
|
|||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (position.StockCode == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 获取历史 K 线数据(需要 longPeriod + 1 根)
|
// 获取历史 K 线数据(需要 longPeriod + 1 根)
|
||||||
|
|||||||
@ -36,14 +36,14 @@ public class RiskParityCalculator : IStrategyCalculator
|
|||||||
var targetAssets = new List<string>();
|
var targetAssets = new List<string>();
|
||||||
var userDefinedWeights = new Dictionary<string, decimal>();
|
var userDefinedWeights = new Dictionary<string, decimal>();
|
||||||
|
|
||||||
if (config.Assets?.Count > 0)
|
if (config.Assets?.Count >0)
|
||||||
{
|
{
|
||||||
targetAssets = config.Assets.Select(a => a.Symbol).ToList();
|
targetAssets = config.Assets.Where(a => a.Symbol != null).Select(a => a.Symbol!).ToList();
|
||||||
userDefinedWeights = config.Assets.ToDictionary(a => a.Symbol, a => a.TargetWeight);
|
userDefinedWeights = config.Assets.Where(a => a.Symbol != null).ToDictionary(a => a.Symbol!, a => a.TargetWeight);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
targetAssets = positions.Select(p => p.StockCode).ToList();
|
targetAssets = positions.Where(p => p.StockCode != null).Select(p => p.StockCode!).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetAssets.Count == 0)
|
if (targetAssets.Count == 0)
|
||||||
@ -219,8 +219,13 @@ public class RiskParityCalculator : IStrategyCalculator
|
|||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (position.StockCode == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
MarketPriceResponse priceResponse;
|
MarketPriceResponse priceResponse;
|
||||||
if (position.AssetType.Equals("Crypto", StringComparison.OrdinalIgnoreCase))
|
if (position.AssetType?.Equals("Crypto", StringComparison.OrdinalIgnoreCase) == true)
|
||||||
{
|
{
|
||||||
priceResponse = await _marketDataService.GetCryptoPriceAsync(position.StockCode);
|
priceResponse = await _marketDataService.GetCryptoPriceAsync(position.StockCode);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,7 +40,7 @@ public class StrategyEngine : IStrategyEngine
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_calculators.TryGetValue(strategy.Type, out var calculator))
|
if (strategy.Type == null || !_calculators.TryGetValue(strategy.Type, out var calculator))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("未找到策略类型 {StrategyType} 的计算器", strategy.Type);
|
_logger.LogWarning("未找到策略类型 {StrategyType} 的计算器", strategy.Type);
|
||||||
return new StrategySignal
|
return new StrategySignal
|
||||||
|
|||||||
@ -3,8 +3,8 @@ namespace AssetManager.Models;
|
|||||||
public class ApiResponse<T>
|
public class ApiResponse<T>
|
||||||
{
|
{
|
||||||
public int code { get; set; }
|
public int code { get; set; }
|
||||||
public T data { get; set; }
|
public T? data { get; set; }
|
||||||
public string message { get; set; }
|
public string? message { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StatusCodes
|
public static class StatusCodes
|
||||||
|
|||||||
@ -2,35 +2,35 @@ namespace AssetManager.Models.DTOs;
|
|||||||
|
|
||||||
public class LoginRequest
|
public class LoginRequest
|
||||||
{
|
{
|
||||||
public string Email { get; set; }
|
public string? Email { get; set; }
|
||||||
public string Password { get; set; }
|
public string? Password { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LoginResponse
|
public class LoginResponse
|
||||||
{
|
{
|
||||||
public string Token { get; set; }
|
public string? Token { get; set; }
|
||||||
public string ExpireAt { get; set; }
|
public string? ExpireAt { get; set; }
|
||||||
public UserBasicInfo User { get; set; }
|
public UserBasicInfo? User { get; set; }
|
||||||
public string UserId { get; set; }
|
public string? UserId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UserBasicInfo
|
public class UserBasicInfo
|
||||||
{
|
{
|
||||||
public string UserName { get; set; }
|
public string? UserName { get; set; }
|
||||||
public string Email { get; set; }
|
public string? Email { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WechatLoginResponse
|
public class WechatLoginResponse
|
||||||
{
|
{
|
||||||
public string Token { get; set; }
|
public string? Token { get; set; }
|
||||||
public string ExpireAt { get; set; }
|
public string? ExpireAt { get; set; }
|
||||||
public UserBasicInfo User { get; set; }
|
public UserBasicInfo? User { get; set; }
|
||||||
public string OpenId { get; set; }
|
public string? OpenId { get; set; }
|
||||||
public string UserId { get; set; }
|
public string? UserId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WechatLoginRequest
|
public class WechatLoginRequest
|
||||||
{
|
{
|
||||||
public string Code { get; set; }
|
public string? Code { get; set; }
|
||||||
public string? NickName { get; set; }
|
public string? NickName { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ public class MarketPriceResponse
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标的代码
|
/// 标的代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Symbol { get; set; }
|
public string? Symbol { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 价格
|
/// 价格
|
||||||
@ -28,7 +28,7 @@ public class MarketPriceResponse
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 资产类型
|
/// 资产类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string AssetType { get; set; }
|
public string? AssetType { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -39,7 +39,7 @@ public class MarketDataResponse
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标的代码
|
/// 标的代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Symbol { get; set; }
|
public string? Symbol { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 时间戳
|
/// 时间戳
|
||||||
@ -74,5 +74,5 @@ public class MarketDataResponse
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 资产类型
|
/// 资产类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string AssetType { get; set; }
|
public string? AssetType { get; set; }
|
||||||
}
|
}
|
||||||
@ -2,66 +2,66 @@ namespace AssetManager.Models.DTOs;
|
|||||||
|
|
||||||
public class CreatePortfolioRequest
|
public class CreatePortfolioRequest
|
||||||
{
|
{
|
||||||
public string name { get; set; }
|
public string? name { get; set; }
|
||||||
public string strategyId { get; set; }
|
public string? strategyId { get; set; }
|
||||||
public string currency { get; set; }
|
public string? currency { get; set; }
|
||||||
public List<StockItem> stocks { get; set; }
|
public List<StockItem>? stocks { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StockItem
|
public class StockItem
|
||||||
{
|
{
|
||||||
public string name { get; set; }
|
public string? name { get; set; }
|
||||||
public string code { get; set; }
|
public string? code { get; set; }
|
||||||
public double price { get; set; }
|
public double price { get; set; }
|
||||||
public int amount { get; set; }
|
public int amount { get; set; }
|
||||||
public string date { get; set; }
|
public string? date { get; set; }
|
||||||
public string currency { get; set; }
|
public string? currency { get; set; }
|
||||||
public string assetType { get; set; } = "Stock"; // Stock / Crypto
|
public string assetType { get; set; } = "Stock"; // Stock / Crypto
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CreatePortfolioResponse
|
public class CreatePortfolioResponse
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? id { get; set; }
|
||||||
public double totalValue { get; set; }
|
public double totalValue { get; set; }
|
||||||
public double returnRate { get; set; }
|
public double returnRate { get; set; }
|
||||||
public string currency { get; set; }
|
public string? currency { get; set; }
|
||||||
public string createdAt { get; set; }
|
public string? createdAt { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PortfolioDetailResponse
|
public class PortfolioDetailResponse
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? id { get; set; }
|
||||||
public string name { get; set; }
|
public string? name { get; set; }
|
||||||
public string currency { get; set; }
|
public string? currency { get; set; }
|
||||||
public string status { get; set; }
|
public string? status { get; set; }
|
||||||
public StrategyInfo strategy { get; set; }
|
public StrategyInfo? strategy { get; set; }
|
||||||
public double portfolioValue { get; set; }
|
public double portfolioValue { get; set; }
|
||||||
public double totalReturn { get; set; }
|
public double totalReturn { get; set; }
|
||||||
public double todayProfit { get; set; }
|
public double todayProfit { get; set; }
|
||||||
public double historicalChange { get; set; }
|
public double historicalChange { get; set; }
|
||||||
public double dailyVolatility { get; set; }
|
public double dailyVolatility { get; set; }
|
||||||
public string todayProfitCurrency { get; set; }
|
public string? todayProfitCurrency { get; set; }
|
||||||
public string logicModel { get; set; }
|
public string? logicModel { get; set; }
|
||||||
public string logicModelStatus { get; set; }
|
public string? logicModelStatus { get; set; }
|
||||||
public string logicModelDescription { get; set; }
|
public string? logicModelDescription { get; set; }
|
||||||
public int totalItems { get; set; }
|
public int totalItems { get; set; }
|
||||||
public double totalRatio { get; set; }
|
public double totalRatio { get; set; }
|
||||||
public List<PositionItem> positions { get; set; }
|
public List<PositionItem>? positions { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StrategyInfo
|
public class StrategyInfo
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? id { get; set; }
|
||||||
public string name { get; set; }
|
public string? name { get; set; }
|
||||||
public string description { get; set; }
|
public string? description { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PositionItem
|
public class PositionItem
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? id { get; set; }
|
||||||
public string stockCode { get; set; }
|
public string? stockCode { get; set; }
|
||||||
public string stockName { get; set; }
|
public string? stockName { get; set; }
|
||||||
public string symbol { get; set; }
|
public string? symbol { get; set; }
|
||||||
public int amount { get; set; }
|
public int amount { get; set; }
|
||||||
public double averagePrice { get; set; }
|
public double averagePrice { get; set; }
|
||||||
public double currentPrice { get; set; }
|
public double currentPrice { get; set; }
|
||||||
@ -71,33 +71,33 @@ public class PositionItem
|
|||||||
public double changeAmount { get; set; }
|
public double changeAmount { get; set; }
|
||||||
public double ratio { get; set; }
|
public double ratio { get; set; }
|
||||||
public double deviationRatio { get; set; }
|
public double deviationRatio { get; set; }
|
||||||
public string currency { get; set; }
|
public string? currency { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TransactionItem
|
public class TransactionItem
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? id { get; set; }
|
||||||
public string portfolioId { get; set; }
|
public string? portfolioId { get; set; }
|
||||||
public string date { get; set; }
|
public string? date { get; set; }
|
||||||
public string time { get; set; }
|
public string? time { get; set; }
|
||||||
public string type { get; set; }
|
public string? type { get; set; }
|
||||||
public string title { get; set; }
|
public string? title { get; set; }
|
||||||
public double amount { get; set; }
|
public double amount { get; set; }
|
||||||
public string currency { get; set; }
|
public string? currency { get; set; }
|
||||||
public string status { get; set; }
|
public string? status { get; set; }
|
||||||
public string remark { get; set; }
|
public string? remark { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GetTransactionsRequest
|
public class GetTransactionsRequest
|
||||||
{
|
{
|
||||||
public string portfolioId { get; set; }
|
public string? portfolioId { get; set; }
|
||||||
public int limit { get; set; }
|
public int limit { get; set; }
|
||||||
public int offset { get; set; }
|
public int offset { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GetTransactionsResponse
|
public class GetTransactionsResponse
|
||||||
{
|
{
|
||||||
public List<TransactionItem> items { get; set; }
|
public List<TransactionItem>? items { get; set; }
|
||||||
public int total { get; set; }
|
public int total { get; set; }
|
||||||
public int page { get; set; }
|
public int page { get; set; }
|
||||||
public int pageSize { get; set; }
|
public int pageSize { get; set; }
|
||||||
@ -105,51 +105,51 @@ public class GetTransactionsResponse
|
|||||||
|
|
||||||
public class CreateTransactionRequest
|
public class CreateTransactionRequest
|
||||||
{
|
{
|
||||||
public string portfolioId { get; set; }
|
public string? portfolioId { get; set; }
|
||||||
public string type { get; set; }
|
public string? type { get; set; }
|
||||||
public string stockCode { get; set; }
|
public string? stockCode { get; set; }
|
||||||
public int amount { get; set; }
|
public int amount { get; set; }
|
||||||
public double price { get; set; }
|
public double price { get; set; }
|
||||||
public string currency { get; set; }
|
public string? currency { get; set; }
|
||||||
public string remark { get; set; }
|
public string? remark { get; set; }
|
||||||
public string assetType { get; set; } = "Stock"; // Stock / Crypto
|
public string assetType { get; set; } = "Stock"; // Stock / Crypto
|
||||||
public string transactionTime { get; set; } // 实际交易时间,可选
|
public string? transactionTime { get; set; } // 实际交易时间,可选
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CreateTransactionResponse
|
public class CreateTransactionResponse
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? id { get; set; }
|
||||||
public double totalAmount { get; set; }
|
public double totalAmount { get; set; }
|
||||||
public string status { get; set; }
|
public string? status { get; set; }
|
||||||
public string createdAt { get; set; }
|
public string? createdAt { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PortfolioListItem
|
public class PortfolioListItem
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? id { get; set; }
|
||||||
public string name { get; set; }
|
public string? name { get; set; }
|
||||||
public string tags { get; set; }
|
public string? tags { get; set; }
|
||||||
public string status { get; set; }
|
public string? status { get; set; }
|
||||||
public string statusType { get; set; }
|
public string? statusType { get; set; }
|
||||||
public string iconChar { get; set; }
|
public string? iconChar { get; set; }
|
||||||
public string iconBgClass { get; set; }
|
public string? iconBgClass { get; set; }
|
||||||
public string iconTextClass { get; set; }
|
public string? iconTextClass { get; set; }
|
||||||
public double value { get; set; }
|
public double value { get; set; }
|
||||||
public string currency { get; set; }
|
public string? currency { get; set; }
|
||||||
public double returnRate { get; set; }
|
public double returnRate { get; set; }
|
||||||
public string returnType { get; set; }
|
public string? returnType { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GetPortfoliosResponse
|
public class GetPortfoliosResponse
|
||||||
{
|
{
|
||||||
public List<PortfolioListItem> items { get; set; }
|
public List<PortfolioListItem>? items { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TotalAssetsResponse
|
public class TotalAssetsResponse
|
||||||
{
|
{
|
||||||
public double totalValue { get; set; }
|
public double totalValue { get; set; }
|
||||||
public string currency { get; set; }
|
public string? currency { get; set; }
|
||||||
public double todayProfit { get; set; }
|
public double todayProfit { get; set; }
|
||||||
public string todayProfitCurrency { get; set; }
|
public string? todayProfitCurrency { get; set; }
|
||||||
public double totalReturnRate { get; set; }
|
public double totalReturnRate { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ public class RiskParityConfig
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 目标资产列表(可选,不指定则使用当前持仓)
|
/// 目标资产列表(可选,不指定则使用当前持仓)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<AssetAllocation> Assets { get; set; }
|
public List<AssetAllocation>? Assets { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -29,7 +29,7 @@ public class AssetAllocation
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标的代码
|
/// 标的代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Symbol { get; set; }
|
public string? Symbol { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 目标权重
|
/// 目标权重
|
||||||
|
|||||||
@ -2,110 +2,110 @@ namespace AssetManager.Models.DTOs;
|
|||||||
|
|
||||||
public class StrategyListResponse
|
public class StrategyListResponse
|
||||||
{
|
{
|
||||||
public List<StrategyItem> items { get; set; }
|
public List<StrategyItem>? items { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StrategyItem
|
public class StrategyItem
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? id { get; set; }
|
||||||
public string iconChar { get; set; }
|
public string? iconChar { get; set; }
|
||||||
public string title { get; set; }
|
public string? title { get; set; }
|
||||||
public string tag { get; set; }
|
public string? tag { get; set; }
|
||||||
public string desc { get; set; }
|
public string? desc { get; set; }
|
||||||
public string bgClass { get; set; }
|
public string? bgClass { get; set; }
|
||||||
public string tagClass { get; set; }
|
public string? tagClass { get; set; }
|
||||||
public string btnText { get; set; }
|
public string? btnText { get; set; }
|
||||||
public string btnClass { get; set; }
|
public string? btnClass { get; set; }
|
||||||
public string[] Tags { get; set; }
|
public string[]? Tags { get; set; }
|
||||||
public string Id { get; set; }
|
public string? Id { get; set; }
|
||||||
public string IconChar { get; set; }
|
public string? IconChar { get; set; }
|
||||||
public string Title { get; set; }
|
public string? Title { get; set; }
|
||||||
public string Tag { get; set; }
|
public string? Tag { get; set; }
|
||||||
public string Desc { get; set; }
|
public string? Desc { get; set; }
|
||||||
public string BgClass { get; set; }
|
public string? BgClass { get; set; }
|
||||||
public string TagClass { get; set; }
|
public string? TagClass { get; set; }
|
||||||
public string BtnText { get; set; }
|
public string? BtnText { get; set; }
|
||||||
public string BtnClass { get; set; }
|
public string? BtnClass { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StrategyDetail
|
public class StrategyDetail
|
||||||
{
|
{
|
||||||
public string Id { get; set; }
|
public string? Id { get; set; }
|
||||||
public string IconChar { get; set; }
|
public string? IconChar { get; set; }
|
||||||
public string Title { get; set; }
|
public string? Title { get; set; }
|
||||||
public string Tag { get; set; }
|
public string? Tag { get; set; }
|
||||||
public string Desc { get; set; }
|
public string? Desc { get; set; }
|
||||||
public string BgClass { get; set; }
|
public string? BgClass { get; set; }
|
||||||
public string TagClass { get; set; }
|
public string? TagClass { get; set; }
|
||||||
public string[] Tags { get; set; }
|
public string[]? Tags { get; set; }
|
||||||
public string BtnText { get; set; }
|
public string? BtnText { get; set; }
|
||||||
public string BtnClass { get; set; }
|
public string? BtnClass { get; set; }
|
||||||
public object Parameters { get; set; }
|
public object? Parameters { get; set; }
|
||||||
public object Backtest { get; set; }
|
public object? Backtest { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StrategyDetailResponse
|
public class StrategyDetailResponse
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? id { get; set; }
|
||||||
public string iconChar { get; set; }
|
public string? iconChar { get; set; }
|
||||||
public string title { get; set; }
|
public string? title { get; set; }
|
||||||
public string riskLevel { get; set; }
|
public string? riskLevel { get; set; }
|
||||||
public string description { get; set; }
|
public string? description { get; set; }
|
||||||
public List<string> tags { get; set; }
|
public List<string>? tags { get; set; }
|
||||||
public List<ParameterItem> parameters { get; set; }
|
public List<ParameterItem>? parameters { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ParameterItem
|
public class ParameterItem
|
||||||
{
|
{
|
||||||
public string name { get; set; }
|
public string? name { get; set; }
|
||||||
public string displayName { get; set; }
|
public string? displayName { get; set; }
|
||||||
public string type { get; set; }
|
public string? type { get; set; }
|
||||||
public string value { get; set; }
|
public string? value { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CreateStrategyRequest
|
public class CreateStrategyRequest
|
||||||
{
|
{
|
||||||
public string name { get; set; }
|
public string? name { get; set; }
|
||||||
public string type { get; set; }
|
public string? type { get; set; }
|
||||||
public string description { get; set; }
|
public string? description { get; set; }
|
||||||
public string riskLevel { get; set; }
|
public string? riskLevel { get; set; }
|
||||||
public List<string> tags { get; set; }
|
public List<string>? tags { get; set; }
|
||||||
public object parameters { get; set; }
|
public object? parameters { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StrategyResponse
|
public class StrategyResponse
|
||||||
{
|
{
|
||||||
public string Id { get; set; }
|
public string? Id { get; set; }
|
||||||
public string Title { get; set; }
|
public string? Title { get; set; }
|
||||||
public string Status { get; set; }
|
public string? Status { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UpdateStrategyRequest
|
public class UpdateStrategyRequest
|
||||||
{
|
{
|
||||||
public string name { get; set; }
|
public string? name { get; set; }
|
||||||
public string type { get; set; }
|
public string? type { get; set; }
|
||||||
public string description { get; set; }
|
public string? description { get; set; }
|
||||||
public string riskLevel { get; set; }
|
public string? riskLevel { get; set; }
|
||||||
public List<string> tags { get; set; }
|
public List<string>? tags { get; set; }
|
||||||
public object parameters { get; set; }
|
public object? parameters { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DeleteStrategyResponse
|
public class DeleteStrategyResponse
|
||||||
{
|
{
|
||||||
public string Id { get; set; }
|
public string? Id { get; set; }
|
||||||
public string Status { get; set; }
|
public string? Status { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StrategyListItemDTO
|
public class StrategyListItemDTO
|
||||||
{
|
{
|
||||||
public string id { get; set; }
|
public string? id { get; set; }
|
||||||
public string userId { get; set; }
|
public string? userId { get; set; }
|
||||||
public string name { get; set; }
|
public string? name { get; set; }
|
||||||
public string type { get; set; }
|
public string? type { get; set; }
|
||||||
public string description { get; set; }
|
public string? description { get; set; }
|
||||||
public List<string> tags { get; set; }
|
public List<string>? tags { get; set; }
|
||||||
public string riskLevel { get; set; }
|
public string? riskLevel { get; set; }
|
||||||
public string config { get; set; }
|
public string? config { get; set; }
|
||||||
public DateTime createdAt { get; set; }
|
public DateTime createdAt { get; set; }
|
||||||
public DateTime updatedAt { get; set; }
|
public DateTime updatedAt { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,17 +8,17 @@ public class StrategySignal
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 策略类型: ma_trend / chandelier_exit / risk_parity
|
/// 策略类型: ma_trend / chandelier_exit / risk_parity
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string StrategyType { get; set; }
|
public string? StrategyType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 信号: BUY / SELL / HOLD / REBALANCE
|
/// 信号: BUY / SELL / HOLD / REBALANCE
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Signal { get; set; }
|
public string? Signal { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标的代码
|
/// 标的代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Symbol { get; set; }
|
public string? Symbol { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 信号强度 (0-1)
|
/// 信号强度 (0-1)
|
||||||
@ -28,7 +28,7 @@ public class StrategySignal
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 信号原因
|
/// 信号原因
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Reason { get; set; }
|
public string? Reason { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 建议价格
|
/// 建议价格
|
||||||
@ -59,12 +59,12 @@ public class PositionSignal
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标的代码
|
/// 标的代码
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Symbol { get; set; }
|
public string? Symbol { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 该标的的信号
|
/// 该标的的信号
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Signal { get; set; }
|
public string? Signal { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 建议数量
|
/// 建议数量
|
||||||
@ -74,7 +74,7 @@ public class PositionSignal
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 信号原因
|
/// 信号原因
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Reason { get; set; }
|
public string? Reason { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 目标权重(风险平价策略用)
|
/// 目标权重(风险平价策略用)
|
||||||
|
|||||||
@ -2,20 +2,20 @@ namespace AssetManager.Models.DTOs;
|
|||||||
|
|
||||||
public class UserInfoResponse
|
public class UserInfoResponse
|
||||||
{
|
{
|
||||||
public string UserName { get; set; }
|
public string? UserName { get; set; }
|
||||||
public string MemberLevel { get; set; }
|
public string? MemberLevel { get; set; }
|
||||||
public int RunningDays { get; set; }
|
public int RunningDays { get; set; }
|
||||||
public string Avatar { get; set; }
|
public string? Avatar { get; set; }
|
||||||
public string Email { get; set; }
|
public string? Email { get; set; }
|
||||||
public string DefaultCurrency { get; set; }
|
public string? DefaultCurrency { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UpdateUserRequest
|
public class UpdateUserRequest
|
||||||
{
|
{
|
||||||
public string UserName { get; set; }
|
public string? UserName { get; set; }
|
||||||
public string Avatar { get; set; }
|
public string? Avatar { get; set; }
|
||||||
public string Email { get; set; }
|
public string? Email { get; set; }
|
||||||
public string DefaultCurrency { get; set; }
|
public string? DefaultCurrency { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UserStatsResponse
|
public class UserStatsResponse
|
||||||
@ -28,6 +28,6 @@ public class UserStatsResponse
|
|||||||
|
|
||||||
public class UpdateUserResponse
|
public class UpdateUserResponse
|
||||||
{
|
{
|
||||||
public string Status { get; set; }
|
public string? Status { get; set; }
|
||||||
public string UserName { get; set; }
|
public string? UserName { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\AssetManager.Data\AssetManager.Data.csproj" />
|
<ProjectReference Include="..\AssetManager.Data\AssetManager.Data.csproj" />
|
||||||
|
<ProjectReference Include="..\AssetManager.Infrastructure\AssetManager.Infrastructure.csproj" />
|
||||||
<ProjectReference Include="..\AssetManager.Models\AssetManager.Models.csproj" />
|
<ProjectReference Include="..\AssetManager.Models\AssetManager.Models.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public class PortfolioService : IPortfolioService
|
|||||||
StrategyId = request.strategyId,
|
StrategyId = request.strategyId,
|
||||||
Name = request.name,
|
Name = request.name,
|
||||||
Currency = request.currency,
|
Currency = request.currency,
|
||||||
TotalValue = (decimal)request.stocks.Sum(s => s.price * s.amount),
|
TotalValue = (decimal)(request.stocks?.Sum(s => s.price * s.amount) ?? 0),
|
||||||
ReturnRate = 0,
|
ReturnRate = 0,
|
||||||
Status = "运行中",
|
Status = "运行中",
|
||||||
CreatedAt = DateTime.Now,
|
CreatedAt = DateTime.Now,
|
||||||
@ -37,8 +37,13 @@ public class PortfolioService : IPortfolioService
|
|||||||
_db.Insertable(portfolio).ExecuteCommand();
|
_db.Insertable(portfolio).ExecuteCommand();
|
||||||
|
|
||||||
// 创建初始持仓
|
// 创建初始持仓
|
||||||
foreach (var stock in request.stocks)
|
foreach (var stock in request.stocks ?? new List<StockItem>())
|
||||||
{
|
{
|
||||||
|
if (stock.code == null || stock.name == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 解析实际买入时间,如果解析失败则用当前时间
|
// 解析实际买入时间,如果解析失败则用当前时间
|
||||||
DateTime buyTime = DateTime.Now;
|
DateTime buyTime = DateTime.Now;
|
||||||
if (!string.IsNullOrEmpty(stock.date))
|
if (!string.IsNullOrEmpty(stock.date))
|
||||||
@ -110,7 +115,7 @@ public class PortfolioService : IPortfolioService
|
|||||||
tags = $"{p.Status} · {p.Currency}",
|
tags = $"{p.Status} · {p.Currency}",
|
||||||
status = p.Status,
|
status = p.Status,
|
||||||
statusType = p.Status == "运行中" ? "green" : "gray",
|
statusType = p.Status == "运行中" ? "green" : "gray",
|
||||||
iconChar = p.Name.Substring(0, 1).ToUpper(),
|
iconChar = p.Name?.Substring(0, 1).ToUpper() ?? "P",
|
||||||
iconBgClass = "bg-blue-100",
|
iconBgClass = "bg-blue-100",
|
||||||
iconTextClass = "text-blue-700",
|
iconTextClass = "text-blue-700",
|
||||||
value = (double)p.TotalValue,
|
value = (double)p.TotalValue,
|
||||||
@ -132,7 +137,7 @@ public class PortfolioService : IPortfolioService
|
|||||||
throw new Exception("User not found");
|
throw new Exception("User not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
string targetCurrency = user.DefaultCurrency;
|
string targetCurrency = user.DefaultCurrency ?? "CNY";
|
||||||
decimal totalValueInTargetCurrency = 0;
|
decimal totalValueInTargetCurrency = 0;
|
||||||
decimal totalCostInTargetCurrency = 0;
|
decimal totalCostInTargetCurrency = 0;
|
||||||
decimal totalTodayProfitInTargetCurrency = 0;
|
decimal totalTodayProfitInTargetCurrency = 0;
|
||||||
@ -151,9 +156,14 @@ public class PortfolioService : IPortfolioService
|
|||||||
|
|
||||||
foreach (var pos in positions)
|
foreach (var pos in positions)
|
||||||
{
|
{
|
||||||
|
if (pos.StockCode == null || pos.Currency == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 获取实时价格
|
// 获取实时价格
|
||||||
MarketPriceResponse priceResponse;
|
MarketPriceResponse priceResponse;
|
||||||
if (pos.AssetType.Equals("Crypto", StringComparison.OrdinalIgnoreCase))
|
if (pos.AssetType?.Equals("Crypto", StringComparison.OrdinalIgnoreCase) == true)
|
||||||
{
|
{
|
||||||
priceResponse = await _marketDataService.GetCryptoPriceAsync(pos.StockCode);
|
priceResponse = await _marketDataService.GetCryptoPriceAsync(pos.StockCode);
|
||||||
}
|
}
|
||||||
@ -220,9 +230,14 @@ public class PortfolioService : IPortfolioService
|
|||||||
|
|
||||||
foreach (var pos in positions)
|
foreach (var pos in positions)
|
||||||
{
|
{
|
||||||
|
if (pos.StockCode == null || pos.Currency == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 获取实时价格
|
// 获取实时价格
|
||||||
MarketPriceResponse priceResponse;
|
MarketPriceResponse priceResponse;
|
||||||
if (pos.AssetType.Equals("Crypto", StringComparison.OrdinalIgnoreCase))
|
if (pos.AssetType?.Equals("Crypto", StringComparison.OrdinalIgnoreCase) == true)
|
||||||
{
|
{
|
||||||
priceResponse = await _marketDataService.GetCryptoPriceAsync(pos.StockCode);
|
priceResponse = await _marketDataService.GetCryptoPriceAsync(pos.StockCode);
|
||||||
}
|
}
|
||||||
@ -383,7 +398,7 @@ public class PortfolioService : IPortfolioService
|
|||||||
TotalAmount = (decimal)(request.price * request.amount),
|
TotalAmount = (decimal)(request.price * request.amount),
|
||||||
Currency = request.currency,
|
Currency = request.currency,
|
||||||
Status = "completed",
|
Status = "completed",
|
||||||
Remark = request.remark,
|
Remark = request.remark ?? string.Empty,
|
||||||
TransactionTime = transactionTime,
|
TransactionTime = transactionTime,
|
||||||
CreatedAt = DateTime.Now
|
CreatedAt = DateTime.Now
|
||||||
};
|
};
|
||||||
@ -445,9 +460,14 @@ public class PortfolioService : IPortfolioService
|
|||||||
decimal totalPortfolioValue = 0;
|
decimal totalPortfolioValue = 0;
|
||||||
foreach (var pos in positions)
|
foreach (var pos in positions)
|
||||||
{
|
{
|
||||||
|
if (pos.StockCode == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 获取实时价格
|
// 获取实时价格
|
||||||
MarketPriceResponse priceResponse;
|
MarketPriceResponse priceResponse;
|
||||||
if (pos.AssetType.Equals("Crypto", StringComparison.OrdinalIgnoreCase))
|
if (pos.AssetType?.Equals("Crypto", StringComparison.OrdinalIgnoreCase) == true)
|
||||||
{
|
{
|
||||||
priceResponse = _marketDataService.GetCryptoPriceAsync(pos.StockCode).GetAwaiter().GetResult();
|
priceResponse = _marketDataService.GetCryptoPriceAsync(pos.StockCode).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,15 +23,15 @@ public class WechatService
|
|||||||
var response = await _httpClient.GetAsync(url);
|
var response = await _httpClient.GetAsync(url);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
var content = await response.Content.ReadAsStringAsync();
|
var content = await response.Content.ReadAsStringAsync();
|
||||||
return JsonSerializer.Deserialize<WechatAuthResult>(content);
|
return JsonSerializer.Deserialize<WechatAuthResult>(content) ?? new WechatAuthResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WechatAuthResult
|
public class WechatAuthResult
|
||||||
{
|
{
|
||||||
public string OpenId { get; set; }
|
public string? OpenId { get; set; }
|
||||||
public string SessionKey { get; set; }
|
public string? SessionKey { get; set; }
|
||||||
public string UnionId { get; set; }
|
public string? UnionId { get; set; }
|
||||||
public int Errcode { get; set; }
|
public int Errcode { get; set; }
|
||||||
public string Errmsg { get; set; }
|
public string? Errmsg { get; set; }
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user