-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathoptimize_meme_strategy.py
More file actions
147 lines (123 loc) · 4.51 KB
/
optimize_meme_strategy.py
File metadata and controls
147 lines (123 loc) · 4.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import sys
import os
import pandas as pd
import numpy as np
import itertools
# Fix path to allow backend imports
sys.path.append(os.path.join(os.getcwd()))
try:
import vectorbt as vbt
from backend import data_fetcher
from backend.strategies_generated import meme_coin_short
except ImportError as e:
print(f"CRITICAL IMPORT ERROR: {e}")
# Cannot proceed without vectorbt or strategy
sys.exit(1)
def generate_synthetic_data(n=1000):
"""Generate synthetic crypto-like data for fallback."""
np.random.seed(42)
# Random walk with some volatility
returns = np.random.normal(0, 0.005, n)
price = 100 * np.exp(np.cumsum(returns))
# Create some trending/pumping periods
# Force a pump at index 200-250
price[200:250] = np.linspace(price[200], price[200]*1.4, 50) + np.random.normal(0, 1, 50)
# Force a dump at 250-300
price[250:300] = np.linspace(price[250], price[250]*0.7, 50) + np.random.normal(0, 1, 50)
df = pd.DataFrame({
"open": price,
"high": price * 1.01,
"low": price * 0.99,
"close": price,
"volume": np.random.randint(100, 1000, n)
}, index=pd.date_range("2024-01-01", periods=n, freq="1h"))
return df
def run_optimization():
print("Starting Meme Coin Strategy Optimization...")
# 1. Get Data
symbol = "XAUUSD"
print(f"Fetching data for {symbol}...")
try:
# Try fetching real data (assuming 5000 bars 1H)
# Note: data_fetcher.fetch_data returns (df, live_price)
result = data_fetcher.fetch_data(symbol, "M15", 5000)
df = result[0]
if df is None or df.empty:
print(f"Real data fetch returned empty. Using synthetic data.")
df = generate_synthetic_data()
except Exception as e:
print(f"Data fetch error: {e}. Using synthetic data.")
df = generate_synthetic_data()
print(f"Data Loaded: {len(df)} candles.")
# 2. Define Parameter Ranges
rsi_thresholds = [50.0, 55.0, 60.0]
adx_thresholds = [15.0, 20.0, 25.0]
ema_fasts = [9, 12]
# Limit slow to reduce combinations
ema_slows = [26]
combinations = list(itertools.product(rsi_thresholds, adx_thresholds, ema_fasts, ema_slows))
print(f"Testing {len(combinations)} combinations...")
results = []
for rsi_t, adx_t, fast, slow in combinations:
if fast >= slow: continue
try:
signals = meme_coin_short.signals(
df,
ema_fast_len=fast,
ema_slow_len=slow,
rsi_threshold=rsi_t,
adx_threshold=adx_t
)
# VectorBT Backtest
# -1 = Short, 0 = Cash.
# Using Portfolio.from_orders with 'targetpercent' handles the rebalancing.
pf = vbt.Portfolio.from_orders(
close=df["close"],
size=signals,
size_type='targetpercent',
freq='1h',
init_cash=10000,
fees=0.001,
slippage=0.001
)
# Check if any trades happened
if len(pf.trades.records) == 0:
# Strategy didn't trade
tres = 0.0
sharpe = 0.0
mdd = 0.0
wr = 0.0
else:
tres = pf.total_return() * 100
sharpe = pf.sharpe_ratio()
mdd = pf.max_drawdown() * 100
wr = pf.trades.win_rate() * 100
res = {
"RSI_Thresh": rsi_t,
"ADX_Thresh": adx_t,
"Fast_EMA": fast,
"Slow_EMA": slow,
"Total Return [%]": tres,
"Sharpe": sharpe,
"Max DD [%]": mdd,
"Win Rate [%]": wr
}
results.append(res)
except Exception as e:
# print(f"Error with params {rsi_t}, {adx_t}: {e}")
pass
# 3. Sort and Report
if not results:
print("No results generated.")
return
results_df = pd.DataFrame(results)
results_df.sort_values(by="Total Return [%]", ascending=False, inplace=True)
print("\nTop 5 Parameter Configurations:")
print(results_df.head(5).to_string(index=False))
# Save results to user?
# Just print for now.
best = results_df.iloc[0]
print("\nBest Configuration:")
print(best.to_string())
if __name__ == "__main__":
run_optimization()