| """ |
| Nifty 50 Ensemble Backtest Script |
| Simulates trading with the ensemble predictions. |
| """ |
| import argparse |
| import pandas as pd |
| import numpy as np |
| from nifty_ensemble_v2 import NiftyEnsembleV2 |
|
|
| def backtest(df, results, threshold=0.55, commission=0.0005, slippage=0.0001): |
| """ |
| Simple backtest: go long when prob_up > threshold, short when < 1-threshold. |
| """ |
| df = df.copy() |
| df['proba_up'] = results['proba'][:, 1] |
| df['pred'] = results['pred'] |
| df['returns'] = df['Close'].pct_change().shift(-1) |
| |
| |
| df['position'] = np.where(df['proba_up'] > threshold, 1, |
| np.where(df['proba_up'] < (1 - threshold), -1, 0)) |
| |
| |
| df['strat_ret'] = df['position'].shift(1) * df['returns'] |
| |
| |
| df['pos_change'] = df['position'].diff().abs() |
| df['costs'] = df['pos_change'] * (commission + slippage) |
| df['strat_ret_net'] = df['strat_ret'] - df['costs'] |
| |
| |
| df['cum_market'] = (1 + df['returns'].fillna(0)).cumprod() |
| df['cum_strat'] = (1 + df['strat_ret_net'].fillna(0)).cumprod() |
| |
| |
| valid = df['strat_ret_net'].dropna() |
| sharpe = valid.mean() / valid.std() * np.sqrt(252 * 375) if valid.std() > 0 else 0 |
| win_rate = (valid > 0).mean() |
| max_dd = ((df['cum_strat'].cummax() - df['cum_strat']) / df['cum_strat'].cummax()).max() |
| |
| print(f"\n{'='*50}") |
| print("BACKTEST RESULTS") |
| print(f"{'='*50}") |
| print(f"Threshold: {threshold}") |
| print(f"Trades: {df['pos_change'].sum():.0f}") |
| print(f"Win Rate: {win_rate:.2%}") |
| print(f"Sharpe (ann): {sharpe:.3f}") |
| print(f"Max Drawdown: {max_dd:.2%}") |
| print(f"Final Return (strat): {(df['cum_strat'].iloc[-1] - 1):.2%}") |
| print(f"Final Return (buy-hold): {(df['cum_market'].iloc[-1] - 1):.2%}") |
| |
| return df |
|
|
| def main(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument('--data', required=True) |
| parser.add_argument('--model', required=True) |
| parser.add_argument('--threshold', type=float, default=0.55) |
| parser.add_argument('--output', default='backtest_results.csv') |
| args = parser.parse_args() |
| |
| df = pd.read_csv(args.data, index_col='Datetime', parse_dates=True) |
| pipe = NiftyEnsembleV2() |
| pipe.load(args.model) |
| results = pipe.predict(df) |
| |
| bt = backtest(results['df'], results, threshold=args.threshold) |
| bt.to_csv(args.output) |
| print(f"\nSaved backtest to {args.output}") |
|
|
| if __name__ == '__main__': |
| main() |
|
|