AssetManager.API
Go to file
OpenClaw Agent 34f06ce941 perf: 优化历史价格获取,优先从缓存表查询
1. 先从 market_kline_cache 缓存表查特定日期价格
2. 缓存命中直接返回,减少 API 调用
3. 缓存未命中才调用 GetHistoricalDataAsync
4. 获取历史数据从 365 天减少到 30 天
5. 大幅减少 Tiingo API 消耗
2026-03-15 10:12:20 +00:00
AssetManager.API feat: 交易后自动触发净值历史重算 2026-03-13 16:53:02 +00:00
AssetManager.Data fix: 添加 PortfolioNavHistory 到 CodeFirst 初始化,删除手动迁移脚本 2026-03-15 08:29:05 +00:00
AssetManager.Infrastructure feat: 添加腾讯财经历史K线数据接口 2026-03-15 10:06:14 +00:00
AssetManager.Models fix: 请求收益曲线时自动回填历史数据 2026-03-13 16:21:31 +00:00
AssetManager.Services perf: 优化历史价格获取,优先从缓存表查询 2026-03-15 10:12:20 +00:00
.dockerignore fix: 请求收益曲线时自动回填历史数据 2026-03-13 16:21:31 +00:00
.env.example fix: 请求收益曲线时自动回填历史数据 2026-03-13 16:21:31 +00:00
.gitignore fix: 请求收益曲线时自动回填历史数据 2026-03-13 16:21:31 +00:00
AssetManager.sln fix: 请求收益曲线时自动回填历史数据 2026-03-13 16:21:31 +00:00
DEPLOY.md fix: 请求收益曲线时自动回填历史数据 2026-03-13 16:21:31 +00:00
docker-compose.yml fix: 请求收益曲线时自动回填历史数据 2026-03-13 16:21:31 +00:00
Dockerfile fix: 请求收益曲线时自动回填历史数据 2026-03-13 16:21:31 +00:00
README.md fix: 请求收益曲线时自动回填历史数据 2026-03-13 16:21:31 +00:00

AssetManager Backend (个人资产策略管理系统)

基于 .NET 8 + MySQL + SqlSugar 构建的高性能资产管理系统后端。采用 Database First (数据库优先) 模式开发,专注于量化策略管理与资产分析。

🛠 技术栈 (Tech Stack)

模块 技术选型 说明
核心框架 .NET 8 Web API 最新长期支持版,高性能
数据库 MySQL 8.0+ 稳定、开源的关系型数据库
ORM SqlSugar 哪怕是 .NET 老手也爱用的国产轻量级 ORM
架构模式 Repository Pattern 仓储模式,解耦业务与数据访问
接口文档 Swagger / Knife4j 在线接口调试

📂 项目结构 (Project Structure)

AssetManager
├── src
│   ├── AssetManager.API            # [入口层] Controllers, DTOs, 全局Filter, IOC配置
│   ├── AssetManager.Services       # [业务层] 核心逻辑 (计算盈亏, 策略信号, 校验)
│   ├── AssetManager.Repository     # [数据层] SqlSugar 仓储实现, UnitOfWork
│   ├── AssetManager.Models         # [实体层] POCO实体 (由数据库自动生成)
│   └── AssetManager.Infrastructure # [基础层] 常用工具类, 外部API调用
└── AssetManager.sln

📊 策略引擎 (Strategy Engine)

功能介绍

策略引擎是系统的核心组件,负责根据配置的策略参数计算交易信号。支持以下三种策略类型:

  1. 双均线策略 (ma_trend) - 经典的趋势跟踪策略,通过短期均线和长期均线的交叉产生买卖信号
  2. 吊灯止损策略 (chandelier_exit) - 趋势跟踪止损策略,通过计算最高价/最低价和 ATR平均真实波幅来设置止损止盈位
  3. 风险平价策略 (risk_parity) - 资产配置策略,通过调整各资产权重使每个资产对组合的风险贡献相等

策略配置示例

1. 双均线策略 (ma_trend)

{
  "maType": "SMA",           // 均线类型SMA(简单移动平均) / EMA(指数移动平均)
  "shortPeriod": 20,         // 短期均线周期
  "longPeriod": 60           // 长期均线周期
}

2. 吊灯止损策略 (chandelier_exit)

{
  "period": 22,              // 周期(通常为 22
  "multiplier": 3.0,         // ATR 倍数(通常为 3.0
  "useClose": false           // 是否使用收盘价计算false 表示用最高价/最低价)
}

3. 风险平价策略 (risk_parity)

{
  "lookbackPeriod": 60,       // 历史数据回看周期
  "rebalanceThreshold": 0.05,  // 再平衡阈值(偏离度超过 5% 触发再平衡)
  "assets": [                  // 目标资产列表(可选,不指定则使用当前持仓)
    { "symbol": "AAPL", "targetWeight": 0.6 },
    { "symbol": "BTC/USD", "targetWeight": 0.4 }
  ]
}

📡 API 示例

🎯 策略 API (Strategy API)

1. 获取策略列表

请求 URL: GET /api/v1/strategy/strategies

请求头:

Authorization: Bearer {token}

响应示例:

{
  "code": 200,
  "data": [
    {
      "Id": "12345678-1234-1234-1234-1234567890ab",
      "Title": "双均线策略",
      "Type": "ma_trend",
      "Description": "经典趋势跟踪策略",
      "RiskLevel": "medium",
      "Tags": ["趋势", "均线"],
      "Parameters": {
        "maType": "SMA",
        "shortPeriod": 20,
        "longPeriod": 60
      },
      "UserId": "user-123",
      "CreatedAt": "2024-01-01T10:00:00",
      "UpdatedAt": "2024-01-01T10:00:00"
    },
    {
      "Id": "87654321-4321-4321-4321-210987654321",
      "Title": "风险平价策略",
      "Type": "risk_parity",
      "Description": "资产配置策略",
      "RiskLevel": "low",
      "Tags": ["资产配置", "风险控制"],
      "Parameters": {
        "lookbackPeriod": 60,
        "rebalanceThreshold": 0.05,
        "assets": [
          { "symbol": "AAPL", "targetWeight": 0.6 },
          { "symbol": "BTC/USD", "targetWeight": 0.4 }
        ]
      },
      "UserId": "user-123",
      "CreatedAt": "2024-01-02T10:00:00",
      "UpdatedAt": "2024-01-02T10:00:00"
    }
  ],
  "message": "Success"
}

2. 获取单个策略详情

请求 URL: GET /api/v1/strategy/{id}

请求头:

Authorization: Bearer {token}

响应示例:

{
  "code": 200,
  "data": {
    "Id": "12345678-1234-1234-1234-1234567890ab",
    "Title": "双均线策略",
    "Type": "ma_trend",
    "Description": "经典趋势跟踪策略",
    "RiskLevel": "medium",
    "Tags": ["趋势", "均线"],
    "Parameters": {
      "maType": "SMA",
      "shortPeriod": 20,
      "longPeriod": 60
    },
    "UserId": "user-123",
    "CreatedAt": "2024-01-01T10:00:00",
    "UpdatedAt": "2024-01-01T10:00:00"
  },
  "message": "Success"
}

3. 创建策略

请求 URL: POST /api/v1/strategy

请求头:

Authorization: Bearer {token}
Content-Type: application/json

请求体示例:

3.1 创建双均线策略

{
  "name": "双均线策略",
  "type": "ma_trend",
  "description": "经典趋势跟踪策略",
  "riskLevel": "medium",
  "tags": ["趋势", "均线"],
  "parameters": {
    "maType": "SMA",
    "shortPeriod": 20,
    "longPeriod": 60
  }
}

3.2 创建风险平价策略

{
  "name": "风险平价策略",
  "type": "risk_parity",
  "description": "资产配置策略",
  "riskLevel": "low",
  "tags": ["资产配置", "风险控制"],
  "parameters": {
    "lookbackPeriod": 60,
    "rebalanceThreshold": 0.05,
    "assets": [
      { "symbol": "AAPL", "targetWeight": 0.6 },
      { "symbol": "BTC/USD", "targetWeight": 0.4 }
    ]
  }
}

3.3 创建吊灯止损策略

{
  "name": "吊灯止损策略",
  "type": "chandelier_exit",
  "description": "趋势跟踪止损策略",
  "riskLevel": "high",
  "tags": ["止损", "趋势"],
  "parameters": {
    "period": 22,
    "multiplier": 3.0,
    "useClose": false
  }
}

响应示例:

{
  "code": 200,
  "data": {
    "Id": "12345678-1234-1234-1234-1234567890ab",
    "Title": "双均线策略",
    "Type": "ma_trend",
    "Description": "经典趋势跟踪策略",
    "RiskLevel": "medium",
    "Tags": ["趋势", "均线"],
    "Parameters": {
      "maType": "SMA",
      "shortPeriod": 20,
      "longPeriod": 60
    },
    "UserId": "user-123",
    "CreatedAt": "2024-01-01T10:00:00",
    "UpdatedAt": "2024-01-01T10:00:00"
  },
  "message": "Strategy created successfully"
}

4. 更新策略

请求 URL: PUT /api/v1/strategy/{id}

请求头:

Authorization: Bearer {token}
Content-Type: application/json

请求体示例:

{
  "name": "双均线策略(更新)",
  "type": "ma_trend",
  "description": "经典趋势跟踪策略",
  "riskLevel": "medium",
  "tags": ["趋势", "均线"],
  "parameters": {
    "maType": "EMA",
    "shortPeriod": 15,
    "longPeriod": 50
  }
}

响应示例:

{
  "code": 200,
  "data": {
    "Id": "12345678-1234-1234-1234-1234567890ab",
    "Title": "双均线策略(更新)",
    "Type": "ma_trend",
    "Description": "经典趋势跟踪策略",
    "RiskLevel": "medium",
    "Tags": ["趋势", "均线"],
    "Parameters": {
      "maType": "EMA",
      "shortPeriod": 15,
      "longPeriod": 50
    },
    "UserId": "user-123",
    "CreatedAt": "2024-01-01T10:00:00",
    "UpdatedAt": "2024-01-15T14:30:00"
  },
  "message": "Strategy updated successfully"
}

5. 删除策略

请求 URL: DELETE /api/v1/strategy/{id}

请求头:

Authorization: Bearer {token}

响应示例:

{
  "code": 200,
  "data": {
    "id": "12345678-1234-1234-1234-1234567890ab",
    "status": "deleted"
  },
  "message": "Strategy deleted successfully"
}

错误响应格式

所有策略接口在发生错误时都会返回统一的错误格式:

{
  "code": 401,
  "data": null,
  "message": "用户未授权"
}

常见错误码:

  • 401: 用户未授权
  • 404: 策略不存在
  • 500: 服务器内部错误

💼 投资组合 API (Portfolio API)

1. 创建投资组合

请求 URL: POST /api/v1/portfolio

请求头:

Authorization: Bearer {token}
Content-Type: application/json

请求体示例:

{
  "name": "我的投资组合",
  "strategyId": "strategy-123",
  "currency": "USD",
  "stocks": [
    {
      "name": "Apple Inc.",
      "code": "AAPL",
      "price": 150.50,
      "amount": 100,
      "date": "2024-01-01",
      "currency": "USD"
    },
    {
      "name": "Microsoft Corp.",
      "code": "MSFT",
      "price": 300.25,
      "amount": 50,
      "date": "2024-01-01",
      "currency": "USD"
    }
  ]
}

响应示例:

{
  "code": 200,
  "data": {
    "id": "port-abc12345",
    "totalValue": 30075.00,
    "returnRate": 0.0,
    "currency": "USD",
    "createdAt": "2024-01-01 10:30:00"
  },
  "message": "success"
}

2. 获取投资组合列表

请求 URL: GET /api/v1/portfolio

请求头:

Authorization: Bearer {token}

响应示例:

{
  "code": 200,
  "data": {
    "items": [
      {
        "id": "port-abc12345",
        "name": "我的投资组合",
        "tags": "科技股",
        "status": "运行中",
        "statusType": "active",
        "iconChar": "P",
        "iconBgClass": "bg-blue-500",
        "iconTextClass": "text-white",
        "value": 30075.00,
        "currency": "USD",
        "returnRate": 0.15,
        "returnType": "positive"
      },
      {
        "id": "port-def67890",
        "name": "保守组合",
        "tags": "债券",
        "status": "运行中",
        "statusType": "active",
        "iconChar": "C",
        "iconBgClass": "bg-green-500",
        "iconTextClass": "text-white",
        "value": 50000.00,
        "currency": "USD",
        "returnRate": 0.08,
        "returnType": "positive"
      }
    ]
  },
  "message": "success"
}

3. 获取总资产情况

请求 URL: GET /api/v1/portfolio/assets

请求头:

Authorization: Bearer {token}

响应示例:

{
  "code": 200,
  "data": {
    "totalValue": 80075.00,
    "currency": "USD",
    "todayProfit": 1250.50,
    "todayProfitCurrency": "USD",
    "totalReturnRate": 0.12
  },
  "message": "success"
}

4. 获取单个投资组合详情

请求 URL: GET /api/v1/portfolio/{id}

请求头:

Authorization: Bearer {token}

响应示例:

{
  "code": 200,
  "data": {
    "id": "port-abc12345",
    "name": "我的投资组合",
    "currency": "CNY",
    "status": "记录中",
    "strategy": {
      "id": "strategy-123",
      "name": "HFEA 风险平价逻辑",
      "description": "目标权重 季度调仓"
    },
    "portfolioValue": 156240.00,
    "totalReturn": 0.4282,
    "todayProfit": 1240.50,
    "historicalChange": 42.82,
    "dailyVolatility": 1240.50,
    "todayProfitCurrency": "CNY",
    "logicModel": "HFEA 风险平价逻辑",
    "logicModelStatus": "监控中",
    "logicModelDescription": "目标权重 季度调仓",
    "totalItems": 2,
    "totalRatio": 100.0,
    "positions": [
      {
        "id": "pos-xyz12345",
        "stockCode": "UPRO",
        "stockName": "UPRO",
        "symbol": "UPRO.US",
        "amount": 142,
        "averagePrice": 500.00,
        "currentPrice": 605.00,
        "totalValue": 85932.00,
        "profit": 12400.00,
        "profitRate": 0.248,
        "changeAmount": 12400.00,
        "ratio": 55.0,
        "deviationRatio": 16.8,
        "currency": "CNY"
      },
      {
        "id": "pos-xyz67890",
        "stockCode": "TMF",
        "stockName": "TMF",
        "symbol": "TMF.US",
        "amount": 800,
        "averagePrice": 90.00,
        "currentPrice": 87.89,
        "totalValue": 70308.00,
        "profit": -3200.50,
        "profitRate": -0.0445,
        "changeAmount": -3200.50,
        "ratio": 45.0,
        "deviationRatio": -4.3,
        "currency": "CNY"
      }
    ]
  },
  "message": "success"
}

5. 获取交易记录

请求 URL: GET /api/v1/portfolio/transactions

请求头:

Authorization: Bearer {token}

查询参数:

  • portfolioId (必填): 投资组合ID
  • limit (可选): 每页记录数,默认 10
  • offset (可选): 偏移量,默认 0

请求示例:

GET /api/v1/portfolio/transactions?portfolioId=port-abc12345&limit=10&offset=0

响应示例:

{
  "code": 200,
  "data": {
    "items": [
      {
        "id": "trans-abc12345",
        "portfolioId": "port-abc12345",
        "date": "2024-02-14",
        "time": "14:30",
        "type": "buy",
        "title": "定期定投 UPRO录入增加",
        "amount": 500.00,
        "currency": "USD",
        "status": "completed",
        "remark": "定期定投"
      },
      {
        "id": "trans-def67890",
        "portfolioId": "port-abc12345",
        "date": "2024-01-01",
        "time": "09:15",
        "type": "sell",
        "title": "季度再平衡 TMF结出减少 200股",
        "amount": 200.00,
        "currency": "USD",
        "status": "completed",
        "remark": "季度再平衡"
      },
      {
        "id": "trans-ghi78901",
        "portfolioId": "port-abc12345",
        "date": "2023-12-15",
        "time": "10:00",
        "type": "buy",
        "title": "建仓买入录入增加",
        "amount": 100000.00,
        "currency": "CNY",
        "status": "completed",
        "remark": "建仓买入"
      },
      {
        "id": "trans-jkl23456",
        "portfolioId": "port-abc12345",
        "date": "2023-12-10",
        "time": "11:20",
        "type": "buy",
        "title": "建仓买入录入增加",
        "amount": 50000.00,
        "currency": "CNY",
        "status": "completed",
        "remark": "建仓买入"
      }
    ],
    "total": 4,
    "page": 1,
    "pageSize": 10
  },
  "message": "success"
}

6. 创建交易

请求 URL: POST /api/v1/portfolio/transactions

请求头:

Authorization: Bearer {token}
Content-Type: application/json

请求体示例:

{
  "portfolioId": "port-abc12345",
  "type": "buy",
  "stockCode": "AAPL",
  "amount": 50,
  "price": 155.00,
  "currency": "USD",
  "remark": "加仓"
}

响应示例:

{
  "code": 200,
  "data": {
    "id": "trans-xyz12345",
    "totalAmount": 7750.00,
    "status": "processing",
    "createdAt": "2024-01-15 14:30:00"
  },
  "message": "success"
}

错误响应格式

所有接口在发生错误时都会返回统一的错误格式:

{
  "code": 401,
  "data": null,
  "message": "用户未授权"
}

常见错误码:

  • 401: 用户未授权
  • 500: 服务器内部错误