Files
quantumbotx/lab/backtester_bollinger_band_v2.py
T
Reynov Christian 78737b6835 Refactor and update bot management and routing
- Update `.gitignore` to include `lab/` for backtesting and raw data.
- Refactor `app.py` to improve error handling and logging.
- Remove deprecated files: `core/bot_logic.py`, `core/bots/base_bot.py`, `core/bots/manager.py`, `core/db/database.py`, `core/routes/api_analysis.py`, `core/routes/api_bots_analysis.py`, `core/strategies/logic_ma.py`, `core/strategies/logic_rsi.py`.
- Modify multiple files to enhance bot management, routing, and strategy handling.
- Update JavaScript and HTML templates for better UI and functionality.
2025-07-31 21:33:44 +08:00

99 lines
3.7 KiB
Python

# backtester_bollinger_v2.py
import pandas as pd
import pandas_ta as ta
import matplotlib.pyplot as plt
def get_profit_multiplier(symbol, lot_size=0.01):
if "500" in symbol or "100" in symbol or "30" in symbol:
return 1 * lot_size
elif "XAU" in symbol:
return 100 * lot_size
elif "JPY" in symbol:
return 1000 * lot_size
else:
return 100000 * lot_size
def run_bollinger_backtest(data_path, symbol, initial_balance=10000):
print(f"Memulai backtest BOLLINGER BANDS (v2) untuk simbol: {symbol}")
LOT_SIZE = 0.01
multiplier = get_profit_multiplier(symbol, LOT_SIZE)
df = pd.read_csv(data_path, parse_dates=['time'])
# Hitung Bollinger Bands dan MA filter
df.ta.bbands(length=20, std=2.0, append=True)
df["ma_filter"] = ta.sma(df["close"], length=50)
df.dropna(inplace=True)
balance, position, trades, equity_curve = initial_balance, None, [], []
cooldown = 0 # Delay antar posisi
print("Memulai Loop Backtest...")
for i in range(1, len(df)):
current = df.iloc[i]
# Cooldown aktif, skip entry
if cooldown > 0:
cooldown -= 1
equity_curve.append(balance)
continue
# Exit logic
if position:
if position['type'] == 'BUY' and current['close'] >= current['BBM_20_2.0']:
profit = (current['close'] - position['entry_price']) * multiplier
balance += profit
trades.append({'type': 'BUY', 'profit': profit})
position = None
cooldown = 3
elif position['type'] == 'SELL' and current['close'] <= current['BBM_20_2.0']:
profit = (position['entry_price'] - current['close']) * multiplier
balance += profit
trades.append({'type': 'SELL', 'profit': profit})
position = None
cooldown = 3
# Entry logic (dengan trend filter)
if not position:
if current['low'] <= current['BBL_20_2.0'] and current['close'] > current['ma_filter']:
position = {'type': 'BUY', 'entry_price': current['close']}
elif current['high'] >= current['BBU_20_2.0'] and current['close'] < current['ma_filter']:
position = {'type': 'SELL', 'entry_price': current['close']}
equity_curve.append(balance)
# Summary
print("\n--- Backtest Selesai ---")
print(f"Balance Awal : ${initial_balance:.2f}")
print(f"Balance Akhir : ${balance:.2f}")
total_profit = balance - initial_balance
print(f"Total P/L : ${total_profit:.2f} ({total_profit/initial_balance*100:.2f}%)")
print(f"Total Trades : {len(trades)}")
# Metrik performa
wins = [t['profit'] for t in trades if t['profit'] > 0]
losses = [t['profit'] for t in trades if t['profit'] <= 0]
winrate = len(wins) / len(trades) * 100 if trades else 0
profit_factor = sum(wins) / abs(sum(losses)) if losses else float('inf')
avg_win = pd.Series(wins).mean() if wins else 0
avg_loss = pd.Series(losses).mean() if losses else 0
print(f"Win Rate : {winrate:.2f}%")
print(f"Profit Factor : {profit_factor:.2f}")
print(f"Avg Win / Loss : ${avg_win:.2f} / ${avg_loss:.2f}")
# Plot
plt.figure(figsize=(12, 6))
plt.plot(df['time'].iloc[-len(equity_curve):], equity_curve, label='Equity Curve')
plt.title(f'Equity Curve - BOLLINGER BANDS v2 on {symbol}')
plt.xlabel('Tanggal')
plt.ylabel('Balance ($)')
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()
if __name__ == '__main__':
symbol_to_test = "EURUSD" # Ganti dengan simbol yang ingin diuji
file_name = "lab/EURUSD_16385_data.csv"
run_bollinger_backtest(file_name, symbol=symbol_to_test)