Signed-off-by: Dinger <quantdinger@gmail.com>
This commit is contained in:
Dinger
2026-03-25 18:08:45 +08:00
parent 05117f3f5b
commit 15c901364b
4 changed files with 199 additions and 12 deletions
+20 -9
View File
@@ -1274,15 +1274,21 @@ class BacktestService:
signals = pd.Series(0, index=df.index)
try:
# Prepare execution environment
# Reset DatetimeIndex to integer so user code can use df.at[0, ...] or df.iloc[0, ...]
df_for_exec = df.copy()
if isinstance(df_for_exec.index, pd.DatetimeIndex):
df_for_exec = df_for_exec.reset_index(drop=False)
if 'time' not in df_for_exec.columns:
df_for_exec.rename(columns={df_for_exec.columns[0]: 'time'}, inplace=True)
local_vars = {
'df': df.copy(),
'open': df['open'],
'high': df['high'],
'low': df['low'],
'close': df['close'],
'volume': df['volume'],
'signals': signals,
'df': df_for_exec,
'open': df_for_exec['open'],
'high': df_for_exec['high'],
'low': df_for_exec['low'],
'close': df_for_exec['close'],
'volume': df_for_exec['volume'],
'signals': pd.Series(0, index=df_for_exec.index),
'np': np,
'pd': pd,
}
@@ -1366,8 +1372,13 @@ import pandas as pd
if not exec_result['success']:
raise RuntimeError(f"Code execution failed: {exec_result['error']}")
# Get the executed df
# Get the executed df, restore DatetimeIndex for signal alignment
executed_df = exec_env.get('df', df)
if isinstance(df.index, pd.DatetimeIndex) and not isinstance(executed_df.index, pd.DatetimeIndex):
if 'time' in executed_df.columns:
executed_df = executed_df.set_index('time')
elif len(executed_df) == len(df):
executed_df.index = df.index
# Validation: if chart signals are provided, df['buy']/df['sell'] must exist for backtest normalization.
# This keeps indicator scripts simple and consistent (chart=buy/sell, execution=normalized in backend).
+8 -3
View File
@@ -670,6 +670,9 @@ class StrategyService:
trading_config['long_ratio'] = long_ratio
trading_config['rebalance_frequency'] = rebalance_frequency
strategy_mode = payload.get('strategy_mode') or 'signal'
strategy_code = payload.get('strategy_code') or ''
with get_db_connection() as db:
cur = db.cursor()
cur.execute(
@@ -678,9 +681,9 @@ class StrategyService:
(user_id, strategy_name, strategy_type, market_category, execution_mode, notification_config,
status, symbol, timeframe, initial_capital, leverage, market_type,
exchange_config, indicator_config, trading_config, ai_model_config, decide_interval,
strategy_group_id, group_base_name,
strategy_group_id, group_base_name, strategy_mode, strategy_code,
created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
""",
(
user_id,
@@ -701,7 +704,9 @@ class StrategyService:
self._dump_json_or_encrypt(payload.get('ai_model_config') or {}, encrypt=False),
int(payload.get('decide_interval') or 300),
strategy_group_id,
group_base_name
group_base_name,
strategy_mode,
strategy_code
)
)
new_id = cur.lastrowid