Compare commits

..

No commits in common. "31c598c4bc64ccfac76820c0665248555d1684d0" and "9741468f3e43ecc81ce563f2a2119c4f24609d67" have entirely different histories.

8 changed files with 110 additions and 427 deletions

View File

@ -22,7 +22,6 @@ public class PortfolioController : ControllerBase
_portfolioService = portfolioService; _portfolioService = portfolioService;
} }
private string GetCurrentUserId() private string GetCurrentUserId()
{ {
return User.FindFirst(ClaimTypes.NameIdentifier)?.Value; return User.FindFirst(ClaimTypes.NameIdentifier)?.Value;

View File

@ -28,33 +28,6 @@ public class StrategyController : ControllerBase
return User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? throw new Exception("User not authenticated"); return User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? throw new Exception("User not authenticated");
} }
private StrategyListItemDTO MapToStrategyListItemDTO(Strategy strategy)
{
List<string> tags = new List<string>();
if (!string.IsNullOrEmpty(strategy.Tags))
{
try
{
tags = System.Text.Json.JsonSerializer.Deserialize<List<string>>(strategy.Tags);
}
catch { }
}
return new StrategyListItemDTO
{
id = strategy.Id,
userId = strategy.UserId,
name = strategy.Alias,
type = strategy.Type,
description = strategy.Description,
tags = tags,
riskLevel = strategy.RiskLevel,
config = strategy.Config,
createdAt = strategy.CreatedAt,
updatedAt = strategy.UpdatedAt
};
}
/// <summary> /// <summary>
/// 获取策略列表 /// 获取策略列表
/// </summary> /// </summary>
@ -63,7 +36,7 @@ public class StrategyController : ControllerBase
/// 此接口用于获取当前登录用户的所有策略列表。 /// 此接口用于获取当前登录用户的所有策略列表。
/// </remarks> /// </remarks>
[HttpGet("strategies")] [HttpGet("strategies")]
public ActionResult<ApiResponse<List<StrategyListItemDTO>>> GetStrategies() public ActionResult<ApiResponse<List<Strategy>>> GetStrategies()
{ {
try try
{ {
@ -71,14 +44,13 @@ public class StrategyController : ControllerBase
var userId = GetCurrentUserId(); var userId = GetCurrentUserId();
var strategies = _strategyService.GetStrategies(userId); var strategies = _strategyService.GetStrategies(userId);
var strategyListItems = strategies.Select(MapToStrategyListItemDTO).ToList();
_logger.LogInformation("Strategies retrieved successfully"); _logger.LogInformation("Strategies retrieved successfully");
return Ok(new ApiResponse<List<StrategyListItemDTO>> return Ok(new ApiResponse<List<Strategy>>
{ {
code = AssetManager.Models.StatusCodes.Success, code = AssetManager.Models.StatusCodes.Success,
data = strategyListItems, data = strategies,
message = "Success" message = "Success"
}); });
} }
@ -86,7 +58,7 @@ public class StrategyController : ControllerBase
{ {
_logger.LogError(ex, "Error retrieving strategies"); _logger.LogError(ex, "Error retrieving strategies");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<List<StrategyListItemDTO>> return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<List<Strategy>>
{ {
code = AssetManager.Models.StatusCodes.InternalServerError, code = AssetManager.Models.StatusCodes.InternalServerError,
data = null, data = null,
@ -104,7 +76,7 @@ public class StrategyController : ControllerBase
/// 此接口用于获取指定策略的详细信息。 /// 此接口用于获取指定策略的详细信息。
/// </remarks> /// </remarks>
[HttpGet("{id}")] [HttpGet("{id}")]
public ActionResult<ApiResponse<StrategyListItemDTO>> GetStrategyById(string id) public ActionResult<ApiResponse<Strategy>> GetStrategyById(string id)
{ {
try try
{ {
@ -112,14 +84,13 @@ public class StrategyController : ControllerBase
var userId = GetCurrentUserId(); var userId = GetCurrentUserId();
var strategy = _strategyService.GetStrategyById(id, userId); var strategy = _strategyService.GetStrategyById(id, userId);
var strategyItem = MapToStrategyListItemDTO(strategy);
_logger.LogInformation($"Strategy {id} retrieved successfully"); _logger.LogInformation($"Strategy {id} retrieved successfully");
return Ok(new ApiResponse<StrategyListItemDTO> return Ok(new ApiResponse<Strategy>
{ {
code = AssetManager.Models.StatusCodes.Success, code = AssetManager.Models.StatusCodes.Success,
data = strategyItem, data = strategy,
message = "Success" message = "Success"
}); });
} }
@ -127,7 +98,7 @@ public class StrategyController : ControllerBase
{ {
_logger.LogError(ex, $"Error retrieving strategy {id}"); _logger.LogError(ex, $"Error retrieving strategy {id}");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<StrategyListItemDTO> return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<Strategy>
{ {
code = AssetManager.Models.StatusCodes.InternalServerError, code = AssetManager.Models.StatusCodes.InternalServerError,
data = null, data = null,
@ -145,7 +116,7 @@ public class StrategyController : ControllerBase
/// 此接口用于创建新的策略。 /// 此接口用于创建新的策略。
/// </remarks> /// </remarks>
[HttpPost] [HttpPost]
public ActionResult<ApiResponse<StrategyListItemDTO>> CreateStrategy([FromBody] CreateStrategyRequest request) public ActionResult<ApiResponse<Strategy>> CreateStrategy([FromBody] CreateStrategyRequest request)
{ {
try try
{ {
@ -153,14 +124,13 @@ public class StrategyController : ControllerBase
var userId = GetCurrentUserId(); var userId = GetCurrentUserId();
var strategy = _strategyService.CreateStrategy(request, userId); var strategy = _strategyService.CreateStrategy(request, userId);
var strategyItem = MapToStrategyListItemDTO(strategy);
_logger.LogInformation($"Strategy {strategy.Id} created successfully"); _logger.LogInformation($"Strategy {strategy.Id} created successfully");
return Ok(new ApiResponse<StrategyListItemDTO> return Ok(new ApiResponse<Strategy>
{ {
code = AssetManager.Models.StatusCodes.Success, code = AssetManager.Models.StatusCodes.Success,
data = strategyItem, data = strategy,
message = "Strategy created successfully" message = "Strategy created successfully"
}); });
} }
@ -168,7 +138,7 @@ public class StrategyController : ControllerBase
{ {
_logger.LogError(ex, "Error creating strategy"); _logger.LogError(ex, "Error creating strategy");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<StrategyListItemDTO> return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<Strategy>
{ {
code = AssetManager.Models.StatusCodes.InternalServerError, code = AssetManager.Models.StatusCodes.InternalServerError,
data = null, data = null,
@ -187,7 +157,7 @@ public class StrategyController : ControllerBase
/// 此接口用于更新指定策略的信息。 /// 此接口用于更新指定策略的信息。
/// </remarks> /// </remarks>
[HttpPut("{id}")] [HttpPut("{id}")]
public ActionResult<ApiResponse<StrategyListItemDTO>> UpdateStrategy(string id, [FromBody] UpdateStrategyRequest request) public ActionResult<ApiResponse<Strategy>> UpdateStrategy(string id, [FromBody] UpdateStrategyRequest request)
{ {
try try
{ {
@ -195,14 +165,13 @@ public class StrategyController : ControllerBase
var userId = GetCurrentUserId(); var userId = GetCurrentUserId();
var strategy = _strategyService.UpdateStrategy(id, request, userId); var strategy = _strategyService.UpdateStrategy(id, request, userId);
var strategyItem = MapToStrategyListItemDTO(strategy);
_logger.LogInformation($"Strategy {id} updated successfully"); _logger.LogInformation($"Strategy {id} updated successfully");
return Ok(new ApiResponse<StrategyListItemDTO> return Ok(new ApiResponse<Strategy>
{ {
code = AssetManager.Models.StatusCodes.Success, code = AssetManager.Models.StatusCodes.Success,
data = strategyItem, data = strategy,
message = "Strategy updated successfully" message = "Strategy updated successfully"
}); });
} }
@ -210,7 +179,7 @@ public class StrategyController : ControllerBase
{ {
_logger.LogError(ex, $"Error updating strategy {id}"); _logger.LogError(ex, $"Error updating strategy {id}");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<StrategyListItemDTO> return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<Strategy>
{ {
code = AssetManager.Models.StatusCodes.InternalServerError, code = AssetManager.Models.StatusCodes.InternalServerError,
data = null, data = null,

View File

@ -32,24 +32,6 @@ public class Strategy
[SugarColumn(ColumnName = "type", Length = 50)] [SugarColumn(ColumnName = "type", Length = 50)]
public string Type { get; set; } public string Type { get; set; }
/// <summary>
/// 策略描述
/// </summary>
[SugarColumn(ColumnName = "description", Length = 500)]
public string Description { get; set; }
/// <summary>
/// 策略标签 (JSON数组)
/// </summary>
[SugarColumn(ColumnName = "tags", IsJson = true)]
public string Tags { get; set; }
/// <summary>
/// 风险等级
/// </summary>
[SugarColumn(ColumnName = "risk_level", Length = 20)]
public string RiskLevel { get; set; }
/// <summary> /// <summary>
/// 策略配置项(周期,阈值,资产配比) /// 策略配置项(周期,阈值,资产配比)
/// </summary> /// </summary>

View File

@ -32,20 +32,13 @@ 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 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 dailyVolatility { get; set; }
public string todayProfitCurrency { get; set; } public string todayProfitCurrency { get; set; }
public string logicModel { get; set; }
public string logicModelStatus { get; set; }
public string logicModelDescription { get; set; }
public int totalItems { get; set; }
public double totalRatio { get; set; }
public List<PositionItem> positions { get; set; } public List<PositionItem> positions { get; set; }
public List<TransactionItem> transactions { get; set; }
} }
public class StrategyInfo public class StrategyInfo
@ -60,16 +53,12 @@ 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 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; }
public double totalValue { get; set; } public double totalValue { get; set; }
public double profit { get; set; } public double profit { get; set; }
public double profitRate { get; set; } public double profitRate { get; set; }
public double changeAmount { get; set; }
public double ratio { get; set; }
public double deviationRatio { get; set; }
public string currency { get; set; } public string currency { get; set; }
} }

View File

@ -71,6 +71,7 @@ public class CreateStrategyRequest
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 string Title { get; set; }
} }
public class StrategyResponse public class StrategyResponse
@ -84,9 +85,6 @@ 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 riskLevel { get; set; }
public List<string> tags { get; set; }
public object parameters { get; set; } public object parameters { get; set; }
} }
@ -95,17 +93,3 @@ 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 string id { get; set; }
public string userId { get; set; }
public string name { get; set; }
public string type { get; set; }
public string description { get; set; }
public List<string> tags { get; set; }
public string riskLevel { get; set; }
public string config { get; set; }
public DateTime createdAt { get; set; }
public DateTime updatedAt { get; set; }
}

View File

@ -137,58 +137,53 @@ public class PortfolioService : IPortfolioService
.Where(pos => pos.PortfolioId == id) .Where(pos => pos.PortfolioId == id)
.ToList(); .ToList();
var totalValue = (double)portfolio.TotalValue; var transactions = _db.Queryable<Transaction>()
var positionItems = positions.Select(pos => .Where(t => t.PortfolioId == id)
{ .OrderByDescending(t => t.TransactionTime)
var positionValue = (double)(pos.Shares * pos.AvgPrice); .Take(5)
var ratio = totalValue > 0 ? (positionValue / totalValue) * 100 : 0; .ToList();
// 假设目标权重为50%,计算偏离比例
var targetWeight = 50.0;
var deviationRatio = ratio - targetWeight;
return new PositionItem
{
id = pos.Id,
stockCode = pos.StockCode,
stockName = pos.StockName,
symbol = $"{pos.StockCode}.US", // 简化处理,实际应该根据市场或数据源确定
amount = (int)pos.Shares,
averagePrice = (double)pos.AvgPrice,
currentPrice = (double)pos.AvgPrice, // 实际应该从市场数据获取
totalValue = positionValue,
profit = 0, // 实际应该计算
profitRate = 0, // 实际应该计算
changeAmount = 0, // 实际应该计算
ratio = ratio,
deviationRatio = deviationRatio,
currency = pos.Currency
};
}).ToList();
return new PortfolioDetailResponse return new PortfolioDetailResponse
{ {
id = portfolio.Id, id = portfolio.Id,
name = portfolio.Name, name = portfolio.Name,
currency = portfolio.Currency, currency = portfolio.Currency,
status = portfolio.Status, // 从数据库获取
strategy = new StrategyInfo strategy = new StrategyInfo
{ {
id = portfolio.StrategyId, id = portfolio.StrategyId,
name = "策略名称", name = "策略名称", // 实际应该从策略表获取
description = "策略描述" description = "策略描述"
}, },
portfolioValue = totalValue, portfolioValue = (double)portfolio.TotalValue,
totalReturn = (double)(portfolio.TotalValue * portfolio.ReturnRate), totalReturn = (double)(portfolio.TotalValue * portfolio.ReturnRate),
todayProfit = 0, // 实际应该计算 todayProfit = 0,
historicalChange = 42.82, // 实际应该计算
dailyVolatility = 1240.50, // 实际应该计算
todayProfitCurrency = portfolio.Currency, todayProfitCurrency = portfolio.Currency,
logicModel = "HFEA 风险平价逻辑", // 实际应该根据策略获取 positions = positions.Select(pos => new PositionItem
logicModelStatus = "监控中", // 实际应该根据策略状态获取 {
logicModelDescription = "目标权重 季度调仓", // 实际应该根据策略配置获取 id = pos.Id,
totalItems = positions.Count, stockCode = pos.StockCode,
totalRatio = 100.0, // 所有持仓比例之和 stockName = pos.StockName,
positions = positionItems amount = (int)pos.Shares,
averagePrice = (double)pos.AvgPrice,
currentPrice = (double)pos.AvgPrice, // 实际应该从市场数据获取
totalValue = (double)(pos.Shares * pos.AvgPrice),
profit = 0,
profitRate = 0,
currency = pos.Currency
}).ToList(),
transactions = transactions.Select(t => new TransactionItem
{
id = t.Id,
portfolioId = t.PortfolioId,
date = t.TransactionTime.ToString("yyyy-MM-dd"),
time = t.TransactionTime.ToString("HH:mm:ss"),
type = t.Type,
title = t.Title,
amount = (double)t.TotalAmount,
currency = t.Currency,
status = t.Status,
remark = t.Remark
}).ToList()
}; };
} }

View File

@ -21,9 +21,6 @@ public class StrategyService : IStrategyService
UserId = userId, UserId = userId,
Alias = request.name, Alias = request.name,
Type = request.type, Type = request.type,
Description = request.description,
Tags = System.Text.Json.JsonSerializer.Serialize(request.tags),
RiskLevel = request.riskLevel,
Config = System.Text.Json.JsonSerializer.Serialize(request.parameters), Config = System.Text.Json.JsonSerializer.Serialize(request.parameters),
CreatedAt = DateTime.Now, CreatedAt = DateTime.Now,
UpdatedAt = DateTime.Now UpdatedAt = DateTime.Now
@ -60,9 +57,6 @@ public class StrategyService : IStrategyService
strategy.Alias = request.name; strategy.Alias = request.name;
strategy.Type = request.type; strategy.Type = request.type;
strategy.Description = request.description;
strategy.Tags = System.Text.Json.JsonSerializer.Serialize(request.tags);
strategy.RiskLevel = request.riskLevel;
strategy.Config = System.Text.Json.JsonSerializer.Serialize(request.parameters); strategy.Config = System.Text.Json.JsonSerializer.Serialize(request.parameters);
strategy.UpdatedAt = DateTime.Now; strategy.UpdatedAt = DateTime.Now;

345
README.md
View File

@ -72,110 +72,13 @@ AssetManager
## 📡 API 示例 ## 📡 API 示例
## 🎯 策略 API (Strategy API) ### 创建策略 API
### 1. 获取策略列表 **请求 URL**: `POST /api/v1/strategies`
**请求 URL**: `GET /api/v1/strategy/strategies`
**请求头**:
```
Authorization: Bearer {token}
```
**响应示例**:
```json
{
"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}
```
**响应示例**:
```json
{
"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 创建双均线策略 #### 1. 创建双均线策略
```json ```json
{ {
@ -192,7 +95,7 @@ Content-Type: application/json
} }
``` ```
#### 3.2 创建风险平价策略 #### 2. 创建风险平价策略
```json ```json
{ {
@ -212,7 +115,7 @@ Content-Type: application/json
} }
``` ```
#### 3.3 创建吊灯止损策略 #### 3. 创建吊灯止损策略
```json ```json
{ {
@ -233,118 +136,12 @@ Content-Type: application/json
```json ```json
{ {
"code": 200, "Id": "12345678-1234-1234-1234-1234567890ab",
"data": { "Title": "双均线策略",
"Id": "12345678-1234-1234-1234-1234567890ab", "Status": "created"
"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
```
**请求体示例**:
```json
{
"name": "双均线策略(更新)",
"type": "ma_trend",
"description": "经典趋势跟踪策略",
"riskLevel": "medium",
"tags": ["趋势", "均线"],
"parameters": {
"maType": "EMA",
"shortPeriod": 15,
"longPeriod": 50
}
}
```
**响应示例**:
```json
{
"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}
```
**响应示例**:
```json
{
"code": 200,
"data": {
"id": "12345678-1234-1234-1234-1234567890ab",
"status": "deleted"
},
"message": "Strategy deleted successfully"
}
```
### 错误响应格式
所有策略接口在发生错误时都会返回统一的错误格式:
```json
{
"code": 401,
"data": null,
"message": "用户未授权"
}
```
**常见错误码**:
- `401`: 用户未授权
- `404`: 策略不存在
- `500`: 服务器内部错误
## 💼 投资组合 API (Portfolio API) ## 💼 投资组合 API (Portfolio API)
### 1. 创建投资组合 ### 1. 创建投资组合
@ -493,56 +290,54 @@ Authorization: Bearer {token}
"data": { "data": {
"id": "port-abc12345", "id": "port-abc12345",
"name": "我的投资组合", "name": "我的投资组合",
"currency": "CNY", "currency": "USD",
"status": "记录中",
"strategy": { "strategy": {
"id": "strategy-123", "id": "strategy-123",
"name": "HFEA 风险平价逻辑", "name": "双均线策略",
"description": "目标权重 季度调仓" "description": "基于短期和长期移动平均线的趋势跟踪策略"
}, },
"portfolioValue": 156240.00, "portfolioValue": 30075.00,
"totalReturn": 0.4282, "totalReturn": 0.15,
"todayProfit": 1240.50, "todayProfit": 1250.50,
"historicalChange": 42.82, "todayProfitCurrency": "USD",
"dailyVolatility": 1240.50,
"todayProfitCurrency": "CNY",
"logicModel": "HFEA 风险平价逻辑",
"logicModelStatus": "监控中",
"logicModelDescription": "目标权重 季度调仓",
"totalItems": 2,
"totalRatio": 100.0,
"positions": [ "positions": [
{ {
"id": "pos-xyz12345", "id": "pos-xyz12345",
"stockCode": "UPRO", "stockCode": "AAPL",
"stockName": "UPRO", "stockName": "Apple Inc.",
"symbol": "UPRO.US", "amount": 100,
"amount": 142, "averagePrice": 150.50,
"averagePrice": 500.00, "currentPrice": 155.00,
"currentPrice": 605.00, "totalValue": 15500.00,
"totalValue": 85932.00, "profit": 450.00,
"profit": 12400.00, "profitRate": 0.03,
"profitRate": 0.248, "currency": "USD"
"changeAmount": 12400.00,
"ratio": 55.0,
"deviationRatio": 16.8,
"currency": "CNY"
}, },
{ {
"id": "pos-xyz67890", "id": "pos-xyz67890",
"stockCode": "TMF", "stockCode": "MSFT",
"stockName": "TMF", "stockName": "Microsoft Corp.",
"symbol": "TMF.US", "amount": 50,
"amount": 800, "averagePrice": 300.25,
"averagePrice": 90.00, "currentPrice": 291.50,
"currentPrice": 87.89, "totalValue": 14575.00,
"totalValue": 70308.00, "profit": -437.50,
"profit": -3200.50, "profitRate": -0.03,
"profitRate": -0.0445, "currency": "USD"
"changeAmount": -3200.50, }
"ratio": 45.0, ],
"deviationRatio": -4.3, "transactions": [
"currency": "CNY" {
"id": "trans-abc12345",
"portfolioId": "port-abc12345",
"date": "2024-01-01",
"time": "10:30:00",
"type": "buy",
"title": "初始建仓",
"amount": 100,
"currency": "USD",
"status": "completed",
"remark": "初始建仓"
} }
] ]
}, },
@ -579,53 +374,29 @@ GET /api/v1/portfolio/transactions?portfolioId=port-abc12345&limit=10&offset=0
{ {
"id": "trans-abc12345", "id": "trans-abc12345",
"portfolioId": "port-abc12345", "portfolioId": "port-abc12345",
"date": "2024-02-14", "date": "2024-01-15",
"time": "14:30", "time": "14:30:00",
"type": "buy", "type": "buy",
"title": "定期定投 UPRO录入增加", "title": "买入AAPL",
"amount": 500.00, "amount": 50,
"currency": "USD", "currency": "USD",
"status": "completed", "status": "completed",
"remark": "定期定投" "remark": "加仓"
}, },
{ {
"id": "trans-def67890", "id": "trans-def67890",
"portfolioId": "port-abc12345", "portfolioId": "port-abc12345",
"date": "2024-01-01", "date": "2024-01-10",
"time": "09:15", "time": "10:15:00",
"type": "sell", "type": "sell",
"title": "季度再平衡 TMF结出减少 200股", "title": "卖出MSFT",
"amount": 200.00, "amount": 25,
"currency": "USD", "currency": "USD",
"status": "completed", "status": "completed",
"remark": "季度再平衡" "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, "total": 25,
"page": 1, "page": 1,
"pageSize": 10 "pageSize": 10
}, },