/* 业务假数据 —— 覆盖各接口的核心展示数据(样板用,连真实后端时不触发) */ import { genEquity, genBenchmark, genRisk, genDailyPnl, genPaperEquity, genDates } from './series' const N = 117 /* ========== 策略 ========== */ export const strategiesMock = { strategies: [ { name: '双均线', class_name: 'AShareDoubleMaStrategy' }, { name: '布林通道', class_name: 'AShareBollStrategy' }, { name: 'ATR 突破', class_name: 'AShareAtrStrategy' }, { name: '全天候(组合)', class_name: 'AllWeatherStrategy' }, ], } export const strategyParamsMock: Record }> = { AShareDoubleMaStrategy: { parameters: ['fast_window', 'slow_window', 'size'], defaults: { fast_window: 10, slow_window: 30, size: 100 } }, AShareBollStrategy: { parameters: ['boll_window', 'boll_dev', 'size'], defaults: { boll_window: 20, boll_dev: 2.0, size: 100 } }, AShareAtrStrategy: { parameters: ['atr_window', 'atr_multiplier', 'size'], defaults: { atr_window: 14, atr_multiplier: 3.0, size: 100 } }, AllWeatherStrategy: { parameters: ['rebalance_day', 'top_n'], defaults: { rebalance_day: 1, top_n: 5 } }, } /* ========== 回测历史任务列表 ========== */ export const taskListMock = { tasks: [ { id: 101, task_id: 'cta_7a92d1f6', type: 'cta', status: 'done', strategy: 'AShareDoubleMaStrategy', symbol: '600519.SH', start: '2024-01-02', end: '2024-06-28', instance: '茅台双均线(10,30)·15m' }, { id: 100, task_id: 'cta_c287f4b5', type: 'cta', status: 'done', strategy: 'AShareBollStrategy', symbol: '000858.SZ', start: '2023-06-01', end: '2024-06-01', instance: '五粮液双均线(5,20)·日线' }, { id: 99, task_id: 'opt_3f8a2c', type: 'optimize', status: 'done', strategy: 'AShareDoubleMaStrategy', symbol: '600519.SH', start: '2023-01-03', end: '2024-06-28', instance: '茅台双均线(10,30)·15m' }, { id: 98, task_id: 'pf_a1b2c3', type: 'portfolio', status: 'done', strategy: 'AllWeatherStrategy', symbol: '中证1000成份', start: '2022-01-04', end: '2024-06-28', instance: '全天候·中证1000·周调仓' }, { id: 97, task_id: 'cta_e5d4c3', type: 'cta', status: 'failed', strategy: 'AShareAtrStrategy', symbol: '300750.SZ', start: '2024-03-01', end: '2024-06-28', instance: '宁德布林(20,2)·15m' }, { id: 96, task_id: 'fc_88aabb', type: 'factor', status: 'done', strategy: '动量因子MOM20', symbol: '全市场', start: '2020-01-02', end: '2024-06-28', instance: '' }, { id: 95, task_id: 'cta_112233', type: 'cta', status: 'running', strategy: 'AShareDoubleMaStrategy', symbol: '510300.SH', start: '2024-01-02', end: '2024-08-12', instance: '茅台双均线(10,30)·15m' }, ], } /* ========== CTA 回测结果 ========== */ export const ctaMetricsMock = { relative_metrics: { total_return: 0.3842, annual_return: 0.3125, alpha: 0.0821, beta: 0.7128, sharpe_ratio: 1.4203, sortino_ratio: 1.8841, information_ratio: 0.9635, annual_volatility: 0.1822, max_drawdown: -0.1278, benchmark_return: 0.0721, benchmark_volatility: 0.1513, }, statistics: { total_return: '0.3842', annual_return: '0.3125', sharpe_ratio: '1.4203', sortino_ratio: '1.8841', max_drawdown: '-0.1278', total_trade_count: '48', win_rate: '0.5417', avg_return: '0.0080', max_dd_duration: '42', daily_net_pnl: '0', total_net_pnl: '384200', total_commission: '4128', total_slippage: '1820', total_turnover: '0.84', }, task_id: 'cta_7a92d1f6', symbol: '600519.SH', start: '2024-01-02', end: '2024-06-28', strategy: 'AShareDoubleMaStrategy', params: { fast_window: 10, slow_window: 30, size: 100 }, status: 'done', } export const equityCurveMock = { equity_curve: genEquity(N) } export const benchmarkCurveMock = (() => { const e = genEquity(N) const b = genBenchmark(N) return { dates: e.map((p) => p.date), strategy: e.map((p) => p.balance), benchmark: b.map((p) => p.balance) } })() export const riskSeriesMock = genRisk(N) export const dailyPnlMock = { daily_pnl: genDailyPnl(N) } export const tradesMock = { trades: [ { datetime: '2024-01-05 09:30:00', direction: 'LONG', offset: 'OPEN', price: 1685.2, volume: 100, vt_symbol: '600519.SH' }, { datetime: '2024-01-18 14:50:00', direction: 'LONG', offset: 'OPEN', price: 1702.5, volume: 100, vt_symbol: '600519.SH' }, { datetime: '2024-02-08 09:35:00', direction: 'SHORT', offset: 'CLOSE', price: 1748.0, volume: 200, vt_symbol: '600519.SH' }, { datetime: '2024-03-04 09:30:00', direction: 'LONG', offset: 'OPEN', price: 1710.6, volume: 100, vt_symbol: '600519.SH' }, { datetime: '2024-04-01 10:15:00', direction: 'SHORT', offset: 'CLOSE', price: 1756.3, volume: 100, vt_symbol: '600519.SH' }, { datetime: '2024-04-22 09:30:00', direction: 'LONG', offset: 'OPEN', price: 1632.8, volume: 100, vt_symbol: '600519.SH' }, { datetime: '2024-05-20 13:40:00', direction: 'SHORT', offset: 'CLOSE', price: 1718.9, volume: 100, vt_symbol: '600519.SH' }, { datetime: '2024-06-12 09:30:00', direction: 'LONG', offset: 'OPEN', price: 1508.2, volume: 100, vt_symbol: '600519.SH' }, ], } export const klineMock = { kline: genDates('2024-01-02', 60).map((date, i) => ({ datetime: date, open: 1680 + Math.sin(i / 5) * 30 + i * 0.4, high: 1690 + Math.sin(i / 5) * 30 + i * 0.4, low: 1670 + Math.sin(i / 5) * 30 + i * 0.4, close: 1685 + Math.sin(i / 5) * 30 + i * 0.4, volume: 1200000 + Math.sin(i / 3) * 400000, })), } export const optResultsMock = { results: [ { params: { fast_window: 5, slow_window: 20 }, statistics: { sharpe_ratio: 1.12, total_return: 0.28, max_drawdown: -0.15 } }, { params: { fast_window: 5, slow_window: 30 }, statistics: { sharpe_ratio: 1.35, total_return: 0.33, max_drawdown: -0.14 } }, { params: { fast_window: 10, slow_window: 20 }, statistics: { sharpe_ratio: 1.48, total_return: 0.37, max_drawdown: -0.12 } }, { params: { fast_window: 10, slow_window: 30 }, statistics: { sharpe_ratio: 1.42, total_return: 0.38, max_drawdown: -0.13 } }, { params: { fast_window: 10, slow_window: 40 }, statistics: { sharpe_ratio: 1.51, total_return: 0.41, max_drawdown: -0.11 } }, { params: { fast_window: 15, slow_window: 30 }, statistics: { sharpe_ratio: 1.36, total_return: 0.35, max_drawdown: -0.14 } }, { params: { fast_window: 20, slow_window: 60 }, statistics: { sharpe_ratio: 1.23, total_return: 0.30, max_drawdown: -0.16 } }, ], } export const logMock = { log: '[2024-06-28 09:30:00] load_data bars=117\n[09:30:01] run_backtesting start\n[09:30:04] run_backtesting done\n[09:30:04] calculate_result shape=(117,25)\n[09:30:04] compute_metrics 27ms\n[09:30:04] write metrics.json done\n' } /* ========== 模拟盘 paper ========== */ export const paperListMock = { accounts: [ { id: 1, name: '茅台双均线·回放', mode: 'replay', interval: 'd', status: 'running', symbols: '600519.SH', initial_capital: 1000000, start_date: '2024-01-02', end_date: '2024-06-28', last_run_date: '2024-06-28', next_run_at: null, checkpoint_date: '2024-06-27', error_msg: null, latest_equity: 1384200, latest_date: '2024-06-28', total_return: 0.3842 }, { id: 2, name: '15分钟动量·实走', mode: 'live', interval: '15m', status: 'running', symbols: '000858.SZ,002594.SZ', initial_capital: 500000, start_date: '2024-05-01', end_date: null, last_run_date: '2024-08-12', next_run_at: '2024-08-13 15:05', checkpoint_date: '2024-08-12', error_msg: null, latest_equity: 521800, latest_date: '2024-08-12', total_return: 0.0436 }, { id: 3, name: '全天候组合·实走', mode: 'live', interval: 'd', status: 'pending', symbols: '中证1000池', initial_capital: 1000000, start_date: '2024-03-01', end_date: null, last_run_date: '2024-08-11', next_run_at: '2024-08-13 15:05', checkpoint_date: '2024-08-11', error_msg: null, latest_equity: 1046200, latest_date: '2024-08-11', total_return: 0.0462 }, { id: 4, name: '布林通道测试', mode: 'replay', interval: 'd', status: 'failed', symbols: '300750.SZ', initial_capital: 300000, start_date: '2024-06-01', end_date: '2024-08-01', last_run_date: '2024-08-01', next_run_at: null, checkpoint_date: null, error_msg: 'load_data bars=0:区间无日线', latest_equity: null, latest_date: null, total_return: null }, ], } export const paperDetailMock = paperListMock.accounts[0] export const paperEquityMock = genPaperEquity(120) export const paperTradesMock = tradesMock.trades.map((t, i) => ({ strategy_id: 'doublema_' + (i % 2), symbol: '600519.SH', direction: t.direction, price: t.price, volume: t.volume, commission: Math.round(t.price * t.volume * 0.0003), rejected: 0, reject_reason: '', bar_date: t.datetime.slice(0, 10), })) export const paperStrategiesMock = [ { strategy_id: 'doublema_0', total_orders: 32, filled: 28, rejected: 4, commission: 1280 }, { strategy_id: 'boll_1', total_orders: 16, filled: 16, rejected: 0, commission: 720 }, ] export const paperPositionsMock = [ { symbol: '600519.SH', volume: 200, frozen: 0, avg_price: 1689.3 }, { symbol: '000858.SZ', volume: 500, frozen: 0, avg_price: 168.2 }, ] export const paperPendingMock = [ { strategy_id: 'doublema_0', symbol: '002594.SZ', side: 'BUY', price: 0, volume: 300, is_market: true, match_session: 'next_open', listing_days: 1200 }, ] /* ========== 实盘 live ========== */ export const liveListMock = { accounts: [ { id: 11, name: '茅台 miniQMT', account: '8888001100', vt_symbol: '600519.SH', strategy_class: 'AShareDoubleMaStrategy', strategy_name: '双均线', setting: '{"fast_window":10,"slow_window":30,"size":100}', status: 'running', interval: 'd', initial_capital: 1000000, connect_wait_sec: 15, init_wait_sec: 8, mini_path: 'D:\\miniQMTuserdata', error_msg: null, created_at: '2024-07-01 10:00:00', updated_at: '2024-08-12 15:05:00', latest_equity: 1384200, latest_date: '2024-08-12', total_return: 0.3842, position_count: 2 }, { id: 12, name: '宁德 miniQMT', account: '8888001101', vt_symbol: '300750.SZ', strategy_class: 'AShareBollStrategy', strategy_name: '布林通道', setting: '{"boll_window":20,"boll_dev":2.0,"size":100}', status: 'stopped', interval: 'd', initial_capital: 500000, connect_wait_sec: 15, init_wait_sec: 8, mini_path: 'D:\\miniQMTuserdata', error_msg: null, created_at: '2024-07-10 14:00:00', updated_at: '2024-08-10 15:05:00', latest_equity: 485200, latest_date: '2024-08-10', total_return: -0.0296, position_count: 1 }, { id: 13, name: '五粮液 miniQMT', account: '8888001102', vt_symbol: '000858.SZ', strategy_class: 'AShareAtrStrategy', strategy_name: 'ATR突破', setting: '{"atr_window":14,"atr_multiplier":3.0,"size":100}', status: 'error', interval: 'd', initial_capital: 300000, connect_wait_sec: 15, init_wait_sec: 8, mini_path: 'D:\\miniQMTuserdata', error_msg: 'xtquant connect timeout (mini_path 未登录)', created_at: '2024-08-01 09:00:00', updated_at: '2024-08-12 09:32:00', latest_equity: null, latest_date: null, total_return: null, position_count: 0 }, ], } export const liveDetailMock = liveListMock.accounts[0] export const livePositionsMock = [ { symbol: '600519.SH', volume: 200, frozen: 0, avg_price: 1689.3, updated_at: '2024-08-12 15:00:00' }, { symbol: '000858.SZ', volume: 500, frozen: 0, avg_price: 168.2, updated_at: '2024-08-12 15:00:00' }, ] export const liveTradesMock = tradesMock.trades.slice(0, 5).map((t, i) => ({ account_id: 11, strategy_name: '双均线', symbol: '600519.SH', direction: t.direction, offset: t.offset, price: t.price, volume: t.volume, traded_at: t.datetime, vt_tradeid: 'xt_' + i, })) export const liveAccountMock = { account_id: 11, date: '2024-08-12', cash: 612400, market_value: 771800, total: 1384200 } export const liveStatusMock = { account_id: 11, status: 'running', name: '茅台 miniQMT', account: '8888001100', vt_symbol: '600519.SH', strategy_name: '双均线', updated_at: '2024-08-12 15:05:00', error_msg: null } /* ========== 组合回测 portfolio ========== */ export const portfolioResultMock = { strategy: 'AllWeatherStrategy', period: { start: '2022-01-04', end: '2024-06-28', trading_days: 596 }, stocks_selected: [ { code: '002594.SZ', name: '比亚迪', amount: 200, avg_cost: 245.3, price: 268.5, value: 53700 }, { code: '300750.SZ', name: '宁德时代', amount: 50, avg_cost: 198.4, price: 212.6, value: 10630 }, { code: '600519.SH', name: '贵州茅台', amount: 10, avg_cost: 1689.3, price: 1718.9, value: 17189 }, { code: '000858.SZ', name: '五粮液', amount: 300, avg_cost: 168.2, price: 158.4, value: 47520 }, { code: '601012.SH', name: '隆基绿能', amount: 800, avg_cost: 32.1, price: 28.6, value: 22880 }, ], trades: tradesMock.trades.slice(0, 6).map((t, i) => ({ datetime: t.datetime, code: '600519.SH', side: i % 2 === 0 ? 'BUY' : 'SELL', amount: 100, filled_amount: 100, price: t.price, filled_price: t.price, commission: 18.5, status: 'FILLED' })), equity_curve: genEquity(180, { from: '2022-01-04' }).map((p) => ({ date: p.date, equity: p.balance })), metrics: { total_return: 0.1523, annual_return: 0.0582, max_drawdown: -0.168, sharpe: 0.78, win_rate_daily: 0.521, win_rate_trade: 0.483, trading_days: 596, }, } /* ========== 策略配置(CRUD) ========== */ export const strategyConfigsMock = { strategies: [ { id: 1, name: '茅台双均线(10,30)', strategy_class: 'AShareDoubleMaStrategy', params: { fast_window: 10, slow_window: 30, size: 100 }, symbol_or_pool: '600519.SH', benchmark: 'hs300', interval: 'd', remark: '茅台日线双均线', created_at: '2024-07-01', updated_at: '2024-08-10' }, { id: 2, name: '宁德布林(20,2)', strategy_class: 'AShareBollStrategy', params: { boll_window: 20, boll_dev: 2, size: 100 }, symbol_or_pool: '300750.SZ', benchmark: 'zz500', interval: 'd', remark: '宁德时代布林通道', created_at: '2024-07-15', updated_at: '2024-08-09' }, { id: 3, name: '全天候组合', strategy_class: 'AllWeatherStrategy', params: { rebalance_day: 1, top_n: 5 }, symbol_or_pool: '中证1000池', benchmark: 'zz500', interval: 'd', remark: '组合主线·月度调仓', created_at: '2024-06-01', updated_at: '2024-08-12' }, { id: 4, name: '五粮液ATR突破', strategy_class: 'AShareAtrStrategy', params: { atr_window: 14, atr_multiplier: 3, size: 100 }, symbol_or_pool: '000858.SZ', benchmark: 'hs300', interval: 'd', remark: '', created_at: '2024-08-01', updated_at: '2024-08-11' }, ], } /* ========== 策略代码文件(在线编辑 mock) ========== */ const DOUBLE_MA_CODE = `"""双均线策略(A股适配 · 基于 vnpy StrategyTemplate)。 fast_window 周期均线上穿 slow_window 周期均线 → 买入; 下穿 → 卖出。定寸 size 股下单(A股 100 股一手)。 """ from typing import List from vnpy_ctastrategy import StrategyTemplate from vnpy.trader.object import BarData class DoubleMaStrategy(StrategyTemplate): """双均线 CTA 策略。""" author = "sanguo" fast_window = 10 slow_window = 30 size = 100 parameters = ["fast_window", "slow_window", "size"] variables = ["fast_ma", "slow_ma"] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): super().__init__(cta_engine, strategy_name, vt_symbol, setting) self.fast_ma = 0.0 self.slow_ma = 0.0 def on_init(self) -> None: self.write_log("策略初始化") self.load_bar(self.slow_window) def on_bar(self, bar: BarData) -> None: am = self.am am.update_bar(bar) if not am.inited: return self.fast_ma = am.sma(self.fast_window, array=True)[-1] self.slow_ma = am.sma(self.slow_window, array=True)[-1] cross_over = self.fast_ma > self.slow_ma cross_below = self.fast_ma < self.slow_ma if cross_over and self.pos == 0: self.buy(bar.close_price + 0.01, self.size) elif cross_below and self.pos > 0: self.sell(bar.close_price - 0.01, self.size) self.put_event() ` const ALL_WEATHER_CODE = `"""聚宽"全天候轮动"策略 · BulletTrade 框架移植。 选股 + 大小盘轮动 + 海外 ETF 兜底 + 涨停盯盘,月度调仓。 数据/下单全部走注入的 provider 和 broker_facade(聚宽风格 API)。 """ import logging import numpy as np from dataclasses import dataclass, field from typing import Any, Callable, List, Optional logger = logging.getLogger(__name__) @dataclass class AllWeatherConfig: stock_num: int = 3 # 持仓数 trend_window: int = 10 # 趋势涨幅窗口 trend_threshold: float = 10.0 # "无敌好行情"阈值 stop_loss_pct: float = 0.92 # 止损线 benchmark: str = "000300.XSHG" class AllWeatherStrategy: """全天候轮动(组合主线策略)。""" def __init__(self, provider: Any, broker: Any = None, config: Optional[AllWeatherConfig] = None): self.provider = provider self.broker = broker self.config = config or AllWeatherConfig() self.hold_list: List[str] = [] def initialize(self, context: Any) -> None: b = self.broker b.set_benchmark(self.config.benchmark) b.run_daily(self.prepare_stock_list, "9:05") b.run_monthly(self.monthly_adjustment, 1, "9:30") b.run_daily(self.stop_loss, "14:00") def monthly_adjustment(self, context: Any) -> None: """月度调仓:大小盘轮动 + 选股 + 调仓下单(详见完整源码)。""" cfg = self.config b_stocks = self._stock_pool("000300.XSHG", context.previous_date) target = self._pick_big_universe(b_stocks, context) for code in target: self.broker.order_target_value(code, 0) # 占位:实际按 target 等权 logger.info("monthly_adjustment target=%s", target) def stop_loss(self, context: Any) -> None: """持仓跌幅超 stop_loss_pct 止损。""" pass # 详见完整实现 ` const BOLL_CODE = `"""布林带通道策略(A股)。价格突破上轨买入,跌破下轨卖出。""" from vnpy_ctastrategy import StrategyTemplate class BollChannelStrategy(StrategyTemplate): author = "sanguo" boll_window = 20 boll_dev = 2.0 size = 100 parameters = ["boll_window", "boll_dev", "size"] variables = ["boll_up", "boll_down"] def on_init(self): self.load_bar(self.boll_window) def on_bar(self, bar): am = self.am am.update_bar(bar) if not am.inited: return self.boll_up, self.boll_down = am.boll(self.boll_window, self.boll_dev) if am.close > self.boll_up and self.pos == 0: self.buy(bar.close_price, self.size) elif am.close < self.boll_down and self.pos > 0: self.sell(bar.close_price, self.size) ` const ATR_CODE = `"""ATR 通道突破策略(A股)。基于 ATR 的动态通道突破。""" from vnpy_ctastrategy import StrategyTemplate class AtrRsiStrategy(StrategyTemplate): author = "sanguo" atr_window = 14 atr_multiplier = 3.0 size = 100 parameters = ["atr_window", "atr_multiplier", "size"] variables = ["atr_value", "entry_price"] def on_init(self): self.load_bar(self.atr_window + 5) def on_bar(self, bar): am = self.am am.update_bar(bar) if not am.inited: return self.atr_value = am.atr(self.atr_window) entry = am.close[-2] + self.atr_value * self.atr_multiplier if am.close > entry and self.pos == 0: self.buy(entry, self.size) self.entry_price = entry ` export interface StrategyFile { name: string dir: string class_name: string type: 'portfolio' | 'cta' lines: number modified: string code: string } export const strategyFilesMock: { files: StrategyFile[] } = { files: [ { name: 'all_weather.py', dir: 'sanguo_portfolio/strategies/', class_name: 'AllWeatherStrategy', type: 'portfolio', lines: 575, modified: '2024-08-12 14:30', code: ALL_WEATHER_CODE }, { name: 'momentum_timing.py', dir: 'sanguo_portfolio/strategies/', class_name: 'MomentumTimingStrategy', type: 'portfolio', lines: 412, modified: '2024-08-10 10:20', code: ALL_WEATHER_CODE }, { name: 'double_ma.py', dir: 'sanguo_live/strategies/', class_name: 'AShareDoubleMaStrategy', type: 'cta', lines: 68, modified: '2024-07-20 09:15', code: DOUBLE_MA_CODE }, { name: 'boll_channel.py', dir: 'sanguo_live/strategies/', class_name: 'AShareBollStrategy', type: 'cta', lines: 32, modified: '2024-07-22 10:00', code: BOLL_CODE }, { name: 'atr_breakout.py', dir: 'sanguo_live/strategies/', class_name: 'AShareAtrStrategy', type: 'cta', lines: 30, modified: '2024-08-01 11:20', code: ATR_CODE }, ], } /* ========== 策略实例(实例层:代码下的参数变体,每实例一键 4 运行) ========== */ export interface StrategyInstance { id: number code_file: string name: string type: 'portfolio' | 'cta' params: Record symbol_or_pool: string interval: string match_session: string status: { backtest: string; replay: string; paper_live: string; live: string } last_return: number | null updated_at: string } export const strategyInstancesMock: { instances: StrategyInstance[] } = { instances: [ { id: 1, code_file: 'all_weather.py', name: '全天候·HS300·月调仓', type: 'portfolio', params: { stock_num: 3, trend_window: 10 }, symbol_or_pool: 'HS300', interval: 'd', match_session: 'next_open', status: { backtest: 'done', replay: 'done', paper_live: 'running', live: '-' }, last_return: 0.1523, updated_at: '2024-08-12' }, { id: 2, code_file: 'all_weather.py', name: '全天候·中证1000·周调仓', type: 'portfolio', params: { stock_num: 5, trend_window: 5 }, symbol_or_pool: '中证1000', interval: 'd', match_session: 'next_open', status: { backtest: 'done', replay: '-', paper_live: '-', live: '-' }, last_return: 0.082, updated_at: '2024-08-10' }, { id: 3, code_file: 'double_ma.py', name: '茅台双均线(10,30)·15m', type: 'cta', params: { fast_window: 10, slow_window: 30, size: 100 }, symbol_or_pool: '600519.SH', interval: '15m', match_session: 'next_open', status: { backtest: 'done', replay: 'done', paper_live: 'running', live: 'running' }, last_return: 0.3842, updated_at: '2024-08-12' }, { id: 4, code_file: 'double_ma.py', name: '五粮液双均线(5,20)·日线', type: 'cta', params: { fast_window: 5, slow_window: 20, size: 100 }, symbol_or_pool: '000858.SZ', interval: 'd', match_session: 'current_close', status: { backtest: 'done', replay: '-', paper_live: '-', live: '-' }, last_return: -0.052, updated_at: '2024-08-08' }, { id: 5, code_file: 'boll_channel.py', name: '宁德布林(20,2)·15m', type: 'cta', params: { boll_window: 20, boll_dev: 2, size: 100 }, symbol_or_pool: '300750.SZ', interval: '15m', match_session: 'next_open', status: { backtest: 'done', replay: '-', paper_live: '-', live: 'stopped' }, last_return: -0.0296, updated_at: '2024-08-10' }, ], } /* ========== 因子 factor ========== */ export const factorListMock = { factors: [ { name: '动量因子 MOM20', category: '动量' }, { name: '换手率 TURN5', category: '量价' }, { name: '波动率 VOL20', category: '波动' }, { name: '市值 SIZE', category: '风格' }, { name: 'ROE_TTM', category: '质量' }, { name: '毛利率 GROSS', category: '质量' }, ], } export const icSummaryMock = { ic_summary: { MOM20: { IC_mean: 0.042, ICIR: 0.51, t_stat: 3.21, positive_ratio: 0.58 }, TURN5: { IC_mean: -0.028, ICIR: -0.33, t_stat: -2.05, positive_ratio: 0.41 }, VOL20: { IC_mean: -0.035, ICIR: -0.42, t_stat: -2.6, positive_ratio: 0.38 }, }, } /* ========== 任务状态(progress 轮询) ========== */ export const taskStatusDoneMock = { task_id: 'cta_7a92d1f6', status: 'done', stage: 'compute_metrics' } export const taskStatusRunningMock = { task_id: 'cta_running01', status: 'running', stage: 'run_backtesting' } // 双轨对账(影子 vs 实盘,§8.2 四指标样例) export const reconcileMock = { pairs: [{ live_account_id: 5, shadow_account_id: 39, strategy: 'channel_test', report: { date: '2026-08-17', live_account_id: 5, shadow_account_id: 39, trades: { live_count: 6, shadow_count: 6, count_match: true, rows: [ { symbol: '510300', side: 'B', live_volume: 20000, shadow_volume: 20000, live_vwap: 3.986, shadow_vwap: 3.982, price_diff_bps: 1.0 }, { symbol: '159915', side: 'B', live_volume: 15000, shadow_volume: 15000, live_vwap: 2.114, shadow_vwap: 2.108, price_diff_bps: 2.8 }, { symbol: '600000', side: 'S', live_volume: 8000, shadow_volume: 8000, live_vwap: 8.912, shadow_vwap: 8.903, price_diff_bps: 1.0 }, ], avg_price_diff_bps: 1.6, pass_price: true, }, positions: { rows: [ { symbol: '510300', live_volume: 20000, shadow_volume: 20000, volume_diff: 0 }, { symbol: '159915', live_volume: 15000, shadow_volume: 15000, volume_diff: 0 }, ], match: true, }, nav: { live_total: 1004218.5, shadow_total: 1003886.2, mtd_deviation_pct: 0.03, pass_nav: true, live_mtd_return_pct: 0.42, shadow_mtd_return_pct: 0.39, }, passed: true, }, }], }