@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user