feat: 回测任务添加最大仓位参数支持

参考跟单配置的实现,为回测任务添加最大仓位金额限制功能。

后端改动:
- 添加数据库迁移文件 V31__add_backtest_max_position_value.sql
- BacktestTask 实体添加 maxPositionValue 字段(BigDecimal?,NULL表示不启用)
- BacktestCreateRequest 添加 maxPositionValue 字段
- BacktestConfigDto 添加 maxPositionValue 字段
- BacktestService 处理 maxPositionValue 的创建、详情和复制
- BacktestExecutionService.taskToCopyTrading 映射 maxPositionValue 参数
- BacktestExecutionService.executeBacktest 在买入逻辑中添加仓位检查
  * 检查条件:当前仓位 + 买入金额 <= 最大仓位
  * 仓位价值计算:quantity * avgPrice
  * 超过限制时跳过该笔买入并记录详细日志
  * 按市场+方向(marketId + outcomeIndex)分别检查

前端改动:
- BacktestList 表单添加最大仓位金额输入框(可选字段)
- 创建回测任务时包含 maxPositionValue
- 回测任务详情中显示 maxPositionValue(仅在配置了时显示)
- 默认最大每日订单数从 50 改为 100
- 多语言翻译新增:
  * backtest.maxPositionValue: 最大仓位金额 / 最大倉位金額 / Max Position Value
  * maxPositionValuePlaceholder: 留空表示不启用最大仓位限制

功能特点:
- 可选参数:留空或为 null 时表示不启用该限制,保持向后兼容
- 单市场单方向限制:按 marketId 和 outcomeIndex 分别计算和限制
- 精确计算:使用 BigDecimal 进行数值比较
- 详细日志:超过限制时记录当前仓位、买入金额、总计等详细信息

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
WrBug
2026-02-09 02:25:24 +08:00
co-authored by Cursor
parent 5487c7c862
commit 20df471683
9 changed files with 60 additions and 6 deletions
+1
View File
@@ -1364,6 +1364,7 @@
"fixedAmountInvalid": "Fixed amount must be greater than 0",
"priceFilters": "Price Filters",
"keywordsPlaceholder": "Please enter keywords, press Enter to add",
"maxPositionValuePlaceholder": "Leave empty to disable max position limit",
"delaySecondsHint": "Delay execution to simulate real copy trading delay",
"supportSellHint": "Whether to follow Leader sell orders",
"sortBy": "Sort By",
+1
View File
@@ -1364,6 +1364,7 @@
"fixedAmountInvalid": "固定金额必须大于 0",
"priceFilters": "价格过滤",
"keywordsPlaceholder": "请输入关键字,按回车添加",
"maxPositionValuePlaceholder": "留空表示不启用最大仓位限制",
"delaySecondsHint": "延迟执行模拟真实跟单延迟",
"supportSellHint": "是否跟随 Leader 卖出",
"sortBy": "排序字段",
+1
View File
@@ -1364,6 +1364,7 @@
"fixedAmountInvalid": "固定金額必須大於 0",
"priceFilters": "價格過濾",
"keywordsPlaceholder": "請輸入關鍵字,按回車添加",
"maxPositionValuePlaceholder": "留空表示不啟用最大倉位限制",
"delaySecondsHint": "延遲執行模擬真實跟單延遲",
"supportSellHint": "是否跟隨 Leader 賣出",
"sortBy": "排序欄位",
+20 -2
View File
@@ -271,7 +271,8 @@ const BacktestList: React.FC = () => {
maxDailyOrders: values.maxDailyOrders,
supportSell: values.supportSell,
keywordFilterMode: values.keywordFilterMode,
keywords: values.keywords
keywords: values.keywords,
maxPositionValue: values.maxPositionValue
}
const response = await backtestService.create(request)
@@ -802,7 +803,7 @@ const BacktestList: React.FC = () => {
layout="vertical"
initialValues={{
maxDailyLoss: 500,
maxDailyOrders: 50,
maxDailyOrders: 100,
supportSell: true,
keywordFilterMode: 'DISABLED',
backtestDays: 7
@@ -978,6 +979,18 @@ const BacktestList: React.FC = () => {
</Col>
</Row>
<Form.Item
label={t('backtest.maxPositionValue') + ' (USDC)'}
name="maxPositionValue"
>
<InputNumber
style={{ width: '100%' }}
placeholder={t('backtest.maxPositionValuePlaceholder') || '留空表示不启用最大仓位限制'}
precision={2}
min={0}
/>
</Form.Item>
<Form.Item
label={t('backtest.supportSell')}
name="supportSell"
@@ -1248,6 +1261,11 @@ const BacktestList: React.FC = () => {
{detailConfig.keywords.join(', ')}
</Descriptions.Item>
)}
{detailConfig.maxPositionValue && (
<Descriptions.Item label={t('backtest.maxPositionValue')}>
{formatUSDC(detailConfig.maxPositionValue)} USDC
</Descriptions.Item>
)}
</Descriptions>
</Card>
)}