Spaces:
Sleeping
Sleeping
| import os | |
| import gradio as gr | |
| import pandas as pd | |
| import numpy as np | |
| import plotly.graph_objs as go | |
| import plotly.express as px | |
| os.environ["GRADIO_ANALYTICS_ENABLED"] = "False" | |
| try: | |
| gr.analytics_enabled = False | |
| except: | |
| pass | |
| # π Strategy Presets | |
| strategy_presets = { | |
| "Aggressive Prop Trader": { | |
| "starting_balance": 2500, "trades_min": 5, "trades_max": 10, "weeks": 12, | |
| "tp1_prob": 0.25, "tp2_prob": 0.4, "tp1_r": 1.2, "tp2_r": 2.4, | |
| "base_risk_pct": 0.015, "profit_target": None, | |
| "fatigue": 0.0, "trump_vol": 0.0, | |
| "description": "High-frequency, high-risk with strong upside potential." | |
| }, | |
| "Conservative Swing Trader": { | |
| "starting_balance": 2500, "trades_min": 2, "trades_max": 5, "weeks": 12, | |
| "tp1_prob": 0.35, "tp2_prob": 0.25, "tp1_r": 0.9, "tp2_r": 1.8, | |
| "base_risk_pct": 0.01, "profit_target": None, | |
| "fatigue": 0.0, "trump_vol": 0.0, | |
| "description": "Lower frequency, prioritizes preservation and steady returns." | |
| }, | |
| "Momentum Scalper": { | |
| "starting_balance": 2500, "trades_min": 4, "trades_max": 8, "weeks": 12, | |
| "tp1_prob": 0.3, "tp2_prob": 0.35, "tp1_r": 1.0, "tp2_r": 2.2, | |
| "base_risk_pct": 0.012, "profit_target": None, | |
| "fatigue": 0.0, "trump_vol": 0.0, | |
| "description": "Intraday momentum strategy for fast-paced trading windows." | |
| }, | |
| "Swing Sniper": { | |
| "starting_balance": 2500, "trades_min": 2, "trades_max": 4, "weeks": 12, | |
| "tp1_prob": 0.2, "tp2_prob": 0.5, "tp1_r": 1.1, "tp2_r": 3.0, | |
| "base_risk_pct": 0.008, "profit_target": None, | |
| "fatigue": 0.0, "trump_vol": 0.0, | |
| "description": "Selective entries with high RR setups. Less frequent." | |
| }, | |
| "Intraday Prop Mode": { | |
| "starting_balance": 2500, "trades_min": 3, "trades_max": 7, "weeks": 12, | |
| "tp1_prob": 0.3, "tp2_prob": 0.3, "tp1_r": 1.0, "tp2_r": 2.0, | |
| "base_risk_pct": 0.02, "profit_target": None, | |
| "fatigue": 0.0, "trump_vol": 0.0, | |
| "description": "Intraday consistency with a balanced reward profile." | |
| } | |
| } | |
| def get_scaled_risk_pct(balance, base_risk_pct): | |
| if balance < 5000: | |
| return base_risk_pct | |
| elif balance < 10000: | |
| return base_risk_pct * 0.75 | |
| elif balance < 20000: | |
| return base_risk_pct * 0.5 | |
| else: | |
| return base_risk_pct * 0.25 | |
| def simulate_tp_strategy_full(starting_balance, trades_min, trades_max, weeks, | |
| tp1_prob, tp2_prob, tp1_r, tp2_r, base_risk_pct, | |
| profit_target=None, fatigue=0.0, trump_vol=0.0): | |
| if tp1_prob + tp2_prob >= 1.0: | |
| return pd.DataFrame(), {"Error": "Invalid probability config. TP1 + TP2 must be < 1.0"} | |
| sl_prob = 1.0 - tp1_prob - tp2_prob | |
| balance = starting_balance | |
| peak = balance | |
| drawdown = 0 | |
| tp1_hits = tp2_hits = sl_hits = 0 | |
| max_win_streak = max_loss_streak = 0 | |
| cur_win_streak = cur_loss_streak = 0 | |
| log = [] | |
| fatigue_multiplier = 1.0 - fatigue * 0.4 # Reduce reward at high fatigue | |
| trump_vol_factor = np.random.normal(1.0, 0.2 * trump_vol) # Adds chaos | |
| for week in range(1, weeks + 1): | |
| if profit_target and balance >= profit_target: break | |
| week_start = balance | |
| num_trades = np.random.randint(trades_min, trades_max + 1) | |
| for _ in range(num_trades): | |
| risk_pct = get_scaled_risk_pct(balance, base_risk_pct) | |
| risk_amount = balance * risk_pct * np.random.uniform(0.9, 1.1) # Risk % w/ some variability | |
| risk_amount *= trump_vol_factor # π Vol boost | |
| # Fatigue loss streak logic | |
| if fatigue > 0.6 and cur_loss_streak >= 3 and np.random.rand() < fatigue * 0.25: | |
| outcome = "SL" | |
| else: | |
| outcome = np.random.choice(["TP1", "TP2", "SL"], p=[tp1_prob, tp2_prob, sl_prob]) | |
| if outcome == "TP1": | |
| balance += risk_amount * tp1_r * fatigue_multiplier | |
| tp1_hits += 1 | |
| cur_win_streak += 1 | |
| cur_loss_streak = 0 | |
| elif outcome == "TP2": | |
| balance += risk_amount * tp2_r * fatigue_multiplier | |
| tp2_hits += 1 | |
| cur_win_streak += 1 | |
| cur_loss_streak = 0 | |
| else: | |
| balance -= risk_amount | |
| sl_hits += 1 | |
| cur_loss_streak += 1 | |
| cur_win_streak = 0 | |
| max_win_streak = max(max_win_streak, cur_win_streak) | |
| max_loss_streak = max(max_loss_streak, cur_loss_streak) | |
| peak = max(peak, balance) | |
| drawdown = max(drawdown, (peak - balance) / peak * 100) | |
| weekly_return = (balance - week_start) / week_start * 100 | |
| log.append({ | |
| "Week": week, "Start Balance": round(week_start, 2), | |
| "End Balance": round(balance, 2), | |
| "Weekly Return (%)": round(weekly_return, 2) | |
| }) | |
| df = pd.DataFrame(log) | |
| returns = df["End Balance"].pct_change().dropna() | |
| volatility = returns.std() * np.sqrt(52) | |
| sharpe_ratio = returns.mean() / returns.std() * np.sqrt(52) if returns.std() > 0 else 0 | |
| score = balance / (1 + drawdown) | |
| summary = { | |
| "Final Balance": round(balance, 2), | |
| "TP1 Hits": tp1_hits, | |
| "TP2 Hits": tp2_hits, | |
| "SL Hits": sl_hits, | |
| "Max Drawdown %": round(drawdown, 2), | |
| "Max Win Streak": max_win_streak, | |
| "Max Loss Streak": max_loss_streak, | |
| "Sharpe Ratio": round(sharpe_ratio, 2), | |
| "EdgeCast Score": round(score, 2) | |
| } | |
| return df, summary | |
| # π Plot | |
| def equity_curve_plot(df, label="Equity Curve"): | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter(x=df["Week"], y=df["End Balance"], mode='lines+markers', name=label)) | |
| fig.update_layout(title=f'π {label}', xaxis_title='Week', yaxis_title='Balance ($)', height=400) | |
| return fig | |
| # π― Preset Tab | |
| def run_preset_strategy_with_toggle(style, enable_fatigue, fatigue, enable_trump, trump_vol): | |
| config = strategy_presets[style] | |
| applied_fatigue = fatigue if enable_fatigue else 0.0 | |
| applied_trump = trump_vol if enable_trump else 0.0 | |
| df, summary = simulate_tp_strategy_full( | |
| config["starting_balance"], config["trades_min"], config["trades_max"], config["weeks"], | |
| config["tp1_prob"], config["tp2_prob"], config["tp1_r"], config["tp2_r"], | |
| config["base_risk_pct"], config["profit_target"], applied_fatigue, applied_trump | |
| ) | |
| return df, summary, equity_curve_plot(df, style), config["description"] | |
| # π οΈ Manual Tab | |
| def run_manual_sim(starting_balance, trades_min, trades_max, weeks, | |
| tp1_prob, tp2_prob, tp1_r, tp2_r, base_risk_pct, profit_target, | |
| fatigue, trump_vol): | |
| df, summary = simulate_tp_strategy_full(starting_balance, trades_min, trades_max, weeks, | |
| tp1_prob, tp2_prob, tp1_r, tp2_r, base_risk_pct, | |
| profit_target, fatigue, trump_vol) | |
| chart = equity_curve_plot(df, "Manual Config") | |
| return df, summary, chart | |
| # βοΈ Manual Battle Mode (Dual Sim) | |
| def dual_manual_battle( | |
| sb1, tmin1, tmax1, w1, tp1a, tp2a, r1a, r2a, risk1, pt1, fat1, trump1, | |
| sb2, tmin2, tmax2, w2, tp1b, tp2b, r1b, r2b, risk2, pt2, fat2, trump2 | |
| ): | |
| df1, s1 = simulate_tp_strategy_full(sb1, tmin1, tmax1, w1, tp1a, tp2a, r1a, r2a, risk1, pt1, fat1, trump1) | |
| df2, s2 = simulate_tp_strategy_full(sb2, tmin2, tmax2, w2, tp1b, tp2b, r1b, r2b, risk2, pt2, fat2, trump2) | |
| s1["Strategy"] = "Manual A" | |
| s2["Strategy"] = "Manual B" | |
| comparison_df = pd.DataFrame([s1, s2]) | |
| comparison_df = comparison_df[["Strategy", "Final Balance", "Sharpe Ratio", "EdgeCast Score", "Max Drawdown %"]] | |
| # π Winners | |
| for col in ["Final Balance", "Sharpe Ratio", "EdgeCast Score"]: | |
| best_val = comparison_df[col].astype(float).max() | |
| comparison_df[col] = [ | |
| f"{val} π" if float(val) == best_val else f"{val}" for val in comparison_df[col] | |
| ] | |
| # Chart | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter(x=df1["Week"], y=df1["End Balance"], name="Manual A")) | |
| fig.add_trace(go.Scatter(x=df2["Week"], y=df2["End Balance"], name="Manual B")) | |
| fig.update_layout(title="βοΈ Manual Strategy Battle", xaxis_title="Week", yaxis_title="Balance") | |
| return comparison_df, fig | |
| # π Leaderboard Tab | |
| def analytics_dashboard(rank_by="EdgeCast Score"): | |
| results = [] | |
| for name, config in strategy_presets.items(): | |
| _, summary = simulate_tp_strategy_full(**{k: v for k, v in config.items() if k != "description"}) | |
| summary["Strategy"] = name | |
| results.append(summary) | |
| df = pd.DataFrame(results) | |
| # Get numeric winners before formatting | |
| winner_vals = { | |
| "Final Balance": df["Final Balance"].max(), | |
| "Sharpe Ratio": df["Sharpe Ratio"].max(), | |
| "EdgeCast Score": df["EdgeCast Score"].max(), | |
| "Max Drawdown %": df["Max Drawdown %"].min() | |
| } | |
| # Sort leaderboard by selected metric | |
| ascending = rank_by == "Max Drawdown %" | |
| df = df.sort_values(rank_by, ascending=ascending).reset_index(drop=True) | |
| # Rank column | |
| df.insert(0, "π Rank", [f"#{i+1}" for i in df.index]) | |
| # π Emoji highlights | |
| for col in winner_vals: | |
| df[col] = df[col].apply(lambda x: f"{round(x, 2)} π" if x == winner_vals[col] else f"{round(x, 2)}") | |
| return df[["π Rank", "Strategy", "Final Balance", "Sharpe Ratio", "EdgeCast Score", "Max Drawdown %"]] | |
| # π Description Tab | |
| def show_descriptions(): | |
| return pd.DataFrame([ | |
| {"Strategy": name, "Description": config["description"]} | |
| for name, config in strategy_presets.items() | |
| ]) | |
| # π¬ Risk Matrix Heatmap | |
| def generate_risk_matrix(): | |
| names = list(strategy_presets.keys()) | |
| scores = { | |
| name: simulate_tp_strategy_full(**{k: v for k, v in cfg.items() if k != "description"})[1]["EdgeCast Score"] | |
| for name, cfg in strategy_presets.items() | |
| } | |
| matrix = np.zeros((len(names), len(names))) | |
| for i, a in enumerate(names): | |
| for j, b in enumerate(names): | |
| matrix[i, j] = abs(scores[a] - scores[b]) | |
| fig = px.imshow( | |
| matrix, | |
| x=names, | |
| y=names, | |
| text_auto=".2f", | |
| color_continuous_scale="RdYlGn_r", | |
| labels={"color": "Score Ξ"}, | |
| title="π§ Risk Matrix (Ξ Score Heatmap)" | |
| ) | |
| fig.update_traces( | |
| hovertemplate="<b>%{y}</b> vs <b>%{x}</b><br>Ξ Score: %{z:.2f}<extra></extra>" | |
| ) | |
| return fig | |
| # π₯ Battle Strategies (Preset vs Preset) | |
| def battle_strategies( | |
| style1, enable_fatigue1, fatigue1, enable_trump1, trump1, | |
| style2, enable_fatigue2, fatigue2, enable_trump2, trump2 | |
| ): | |
| if style1 == "None" or style2 == "None": | |
| return pd.DataFrame([{"β οΈ Error": "Please select two valid strategies."}]), go.Figure() | |
| if style1 == style2: | |
| return pd.DataFrame([{"β οΈ Error": "Please select two different strategies."}]), go.Figure() | |
| fatigue_a = fatigue1 if enable_fatigue1 else 0.0 | |
| trump_a = trump1 if enable_trump1 else 0.0 | |
| fatigue_b = fatigue2 if enable_fatigue2 else 0.0 | |
| trump_b = trump2 if enable_trump2 else 0.0 | |
| try: | |
| config1 = strategy_presets[style1] | |
| config2 = strategy_presets[style2] | |
| df1, s1 = simulate_tp_strategy_full( | |
| config1["starting_balance"], config1["trades_min"], config1["trades_max"], config1["weeks"], | |
| config1["tp1_prob"], config1["tp2_prob"], config1["tp1_r"], config1["tp2_r"], | |
| config1["base_risk_pct"], config1["profit_target"], fatigue_a, trump_a | |
| ) | |
| df2, s2 = simulate_tp_strategy_full( | |
| config2["starting_balance"], config2["trades_min"], config2["trades_max"], config2["weeks"], | |
| config2["tp1_prob"], config2["tp2_prob"], config2["tp1_r"], config2["tp2_r"], | |
| config2["base_risk_pct"], config2["profit_target"], fatigue_b, trump_b | |
| ) | |
| s1["Strategy"], s2["Strategy"] = style1, style2 | |
| df_compare = pd.DataFrame([s1, s2])[["Strategy", "Final Balance", "Sharpe Ratio", "EdgeCast Score", "Max Drawdown %"]] | |
| for col in ["Final Balance", "Sharpe Ratio", "EdgeCast Score"]: | |
| best_val = df_compare[col].astype(float).max() | |
| df_compare[col] = [f"{val} π" if float(val) == best_val else val for val in df_compare[col]] | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter(x=df1["Week"], y=df1["End Balance"], name=style1)) | |
| fig.add_trace(go.Scatter(x=df2["Week"], y=df2["End Balance"], name=style2)) | |
| fig.update_layout(title=f"π₯ {style1} vs {style2}", xaxis_title="Week", yaxis_title="Balance") | |
| return df_compare, fig | |
| except Exception as e: | |
| return pd.DataFrame([{"Error": str(e)}]), go.Figure() | |
| # π App UI Launch | |
| app = gr.TabbedInterface( | |
| interface_list=[ | |
| # π― Preset Mode | |
| gr.Interface( | |
| fn=run_preset_strategy_with_toggle, | |
| inputs=[ | |
| gr.Dropdown(choices=list(strategy_presets.keys()), label="Select Strategy"), | |
| gr.Checkbox(label="Enable Fatigue"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="Fatigue Level"), | |
| gr.Checkbox(label="Enable Trump Volatility"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="Trump Volatility Index") | |
| ], | |
| outputs=["dataframe", "json", gr.Plot(), "text"], | |
| title="π― Preset Mode" | |
| ), | |
| # π οΈ Manual Config | |
| gr.Interface( | |
| fn=run_manual_sim, | |
| inputs=[ | |
| gr.Slider(100, 20000, 2500, label="Start Balance"), | |
| gr.Slider(1, 10, 3, label="Trades Min"), | |
| gr.Slider(1, 15, 7, label="Trades Max"), | |
| gr.Slider(1, 52, 12, label="Weeks"), | |
| gr.Slider(0, 1, 0.3, step=0.05, label="TP1 %"), | |
| gr.Slider(0, 1, 0.3, step=0.05, label="TP2 %"), | |
| gr.Slider(0.1, 5.0, 1.0, step=0.1, label="TP1 R"), | |
| gr.Slider(0.1, 20.0, 2.0, step=0.1, label="TP2 R"), | |
| gr.Slider(0.001, 0.05, 0.01, step=0.001, label="Risk %"), | |
| gr.Slider(0, 100000, 0, step=500, label="Profit Target π°"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="Fatigue Level"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="Trump Volatility Index") | |
| ], | |
| outputs=["dataframe", "json", gr.Plot()], | |
| title="π οΈ Manual Config" | |
| ), | |
| # π₯ Battle Mode β Preset | |
| gr.Interface( | |
| fn=battle_strategies, | |
| inputs=[ | |
| gr.Dropdown(choices=["None"] + list(strategy_presets.keys()), value="None", label="Strategy A"), | |
| gr.Checkbox(label="Enable Fatigue for A"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="Fatigue Level A"), | |
| gr.Checkbox(label="Enable Trump Volatility for A"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="Trump Volatility A"), | |
| gr.Dropdown(choices=["None"] + list(strategy_presets.keys()), value="None", label="Strategy B"), | |
| gr.Checkbox(label="Enable Fatigue for B"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="Fatigue Level B"), | |
| gr.Checkbox(label="Enable Trump Volatility for B"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="Trump Volatility B"), | |
| ], | |
| outputs=["dataframe", gr.Plot()], | |
| title="π₯ Battle Mode" | |
| ), | |
| # π§ͺ Manual Battle Mode | |
| # π§ͺ Manual Battle Mode (Slider Version) | |
| gr.Interface( | |
| fn=dual_manual_battle, | |
| inputs=[ | |
| # Config A | |
| gr.Slider(100, 20000, 2500, label="A: Start Balance"), | |
| gr.Slider(1, 10, 3, label="A: Trades Min"), | |
| gr.Slider(1, 15, 7, label="A: Trades Max"), | |
| gr.Slider(1, 52, 12, label="A: Weeks"), | |
| gr.Slider(0, 1, 0.3, step=0.05, label="A: TP1 %"), | |
| gr.Slider(0, 1, 0.3, step=0.05, label="A: TP2 %"), | |
| gr.Slider(0.1, 5.0, 1.0, step=0.1, label="A: TP1 R"), | |
| gr.Slider(0.1, 20.0, 2.0, step=0.1, label="A: TP2 R"), | |
| gr.Slider(0.001, 0.05, 0.01, step=0.001, label="A: Risk %"), | |
| gr.Slider(0, 100000, 0, step=500, label="A: Profit Target"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="A: Fatigue"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="A: Trump Volatility"), | |
| # Config B | |
| gr.Slider(100, 20000, 2500, label="B: Start Balance"), | |
| gr.Slider(1, 10, 3, label="B: Trades Min"), | |
| gr.Slider(1, 15, 7, label="B: Trades Max"), | |
| gr.Slider(1, 52, 12, label="B: Weeks"), | |
| gr.Slider(0, 1, 0.3, step=0.05, label="B: TP1 %"), | |
| gr.Slider(0, 1, 0.3, step=0.05, label="B: TP2 %"), | |
| gr.Slider(0.1, 5.0, 1.0, step=0.1, label="B: TP1 R"), | |
| gr.Slider(0.1, 20.0, 2.0, step=0.1, label="B: TP2 R"), | |
| gr.Slider(0.001, 0.05, 0.01, step=0.001, label="B: Risk %"), | |
| gr.Slider(0, 100000, 0, step=500, label="B: Profit Target"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="B: Fatigue"), | |
| gr.Slider(0, 1, 0.0, step=0.1, label="B: Trump Volatility") | |
| ], | |
| outputs=["dataframe", gr.Plot()], | |
| title="π§ͺ Manual Battle Mode" | |
| ), | |
| # π Analytics Leaderboard | |
| gr.Interface( | |
| fn=analytics_dashboard, | |
| inputs=gr.Dropdown( | |
| choices=["EdgeCast Score", "Final Balance", "Sharpe Ratio", "Max Drawdown %"], | |
| value="EdgeCast Score", | |
| label="Sort leaderboard by:" | |
| ), | |
| outputs="dataframe", | |
| title="π Analytics Leaderboard" | |
| ), | |
| # π Strategy Descriptions | |
| gr.Interface( | |
| fn=show_descriptions, | |
| inputs=[], outputs="dataframe", | |
| title="π Strategy Descriptions" | |
| ), | |
| # π¬ Risk Matrix Heatmap | |
| gr.Interface( | |
| fn=generate_risk_matrix, | |
| inputs=[], outputs=gr.Plot(), | |
| title="π¬ Risk Matrix" | |
| ) | |
| ], | |
| tab_names=["Preset", "Manual", "Battle", "Manual Battle", "Analytics", "Descriptions", "Risk Matrix"], | |
| title="EdgeCast β Strategy Simulation Suite" | |
| ) | |
| app.launch() | |