Cycles/test_bbrsi.py

146 lines
7.4 KiB
Python
Raw Normal View History

2025-05-20 18:28:53 +08:00
import logging
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
from cycles.utils.storage import Storage
from cycles.Analysis.strategies import Strategy
2025-05-20 18:28:53 +08:00
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler("backtest.log"),
logging.StreamHandler()
]
)
config = {
"start_date": "2023-01-01",
"stop_date": "2024-01-01",
2025-05-20 18:28:53 +08:00
"data_file": "btcusd_1-min_data.csv"
}
config_strategy = {
"bb_width": 0.05,
"bb_period": 20,
"rsi_period": 14,
"trending": {
"rsi_threshold": [30, 70],
"bb_std_dev_multiplier": 2.5,
},
"sideways": {
"rsi_threshold": [40, 60],
"bb_std_dev_multiplier": 1.8,
},
"strategy_name": "MarketRegimeStrategy",
"SqueezeStrategy": True
}
2025-05-20 18:28:53 +08:00
IS_DAY = False
2025-05-20 18:28:53 +08:00
if __name__ == "__main__":
# Load data
2025-05-20 18:28:53 +08:00
storage = Storage(logging=logging)
data = storage.load_data(config["data_file"], config["start_date"], config["stop_date"])
# Run strategy
strategy = Strategy(config=config_strategy, logging=logging)
processed_data = strategy.run(data.copy(), config_strategy["strategy_name"])
2025-05-20 18:28:53 +08:00
# Get buy and sell signals
buy_condition = processed_data.get('BuySignal', pd.Series(False, index=processed_data.index)).astype(bool)
sell_condition = processed_data.get('SellSignal', pd.Series(False, index=processed_data.index)).astype(bool)
2025-05-20 18:28:53 +08:00
buy_signals = processed_data[buy_condition]
sell_signals = processed_data[sell_condition]
2025-05-20 18:28:53 +08:00
# Plot the data with seaborn library
if processed_data is not None and not processed_data.empty:
2025-05-20 18:28:53 +08:00
# Create a figure with two subplots, sharing the x-axis
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(16, 8), sharex=True)
2025-05-20 18:28:53 +08:00
strategy_name = config_strategy["strategy_name"]
# Plot 1: Close Price and Strategy-Specific Bands/Levels
sns.lineplot(x=processed_data.index, y='close', data=processed_data, label='Close Price', ax=ax1)
if strategy_name == "MarketRegimeStrategy":
if 'UpperBand' in processed_data.columns and 'LowerBand' in processed_data.columns:
sns.lineplot(x=processed_data.index, y='UpperBand', data=processed_data, label='Upper Band (BB)', ax=ax1)
sns.lineplot(x=processed_data.index, y='LowerBand', data=processed_data, label='Lower Band (BB)', ax=ax1)
else:
logging.warning("MarketRegimeStrategy: UpperBand or LowerBand not found for plotting.")
elif strategy_name == "CryptoTradingStrategy":
if 'UpperBand_15m' in processed_data.columns and 'LowerBand_15m' in processed_data.columns:
sns.lineplot(x=processed_data.index, y='UpperBand_15m', data=processed_data, label='Upper Band (15m)', ax=ax1)
sns.lineplot(x=processed_data.index, y='LowerBand_15m', data=processed_data, label='Lower Band (15m)', ax=ax1)
else:
logging.warning("CryptoTradingStrategy: UpperBand_15m or LowerBand_15m not found for plotting.")
if 'StopLoss' in processed_data.columns:
sns.lineplot(x=processed_data.index, y='StopLoss', data=processed_data, label='Stop Loss', ax=ax1, linestyle='--', color='orange')
if 'TakeProfit' in processed_data.columns:
sns.lineplot(x=processed_data.index, y='TakeProfit', data=processed_data, label='Take Profit', ax=ax1, linestyle='--', color='purple')
2025-05-20 18:28:53 +08:00
# Plot Buy/Sell signals on Price chart
if not buy_signals.empty:
ax1.scatter(buy_signals.index, buy_signals['close'], color='green', marker='o', s=10, label='Buy Signal', zorder=5)
2025-05-20 18:28:53 +08:00
if not sell_signals.empty:
ax1.scatter(sell_signals.index, sell_signals['close'], color='red', marker='o', s=10, label='Sell Signal', zorder=5)
ax1.set_title(f'Price and Signals ({strategy_name})')
2025-05-20 18:28:53 +08:00
ax1.set_ylabel('Price')
ax1.legend()
ax1.grid(True)
# Plot 2: RSI and Strategy-Specific Thresholds
rsi_col_name = 'RSI' if strategy_name == "MarketRegimeStrategy" else 'RSI_15m'
if rsi_col_name in processed_data.columns:
sns.lineplot(x=processed_data.index, y=rsi_col_name, data=processed_data, label=f'{rsi_col_name} (' + str(config_strategy.get("rsi_period", 14)) + ')', ax=ax2, color='purple')
if strategy_name == "MarketRegimeStrategy":
# Assuming trending thresholds are what we want to show generally
ax2.axhline(config_strategy.get("trending", {}).get("rsi_threshold", [30,70])[1], color='red', linestyle='--', linewidth=0.8, label=f'Overbought (' + str(config_strategy.get("trending", {}).get("rsi_threshold", [30,70])[1]) + ')')
ax2.axhline(config_strategy.get("trending", {}).get("rsi_threshold", [30,70])[0], color='green', linestyle='--', linewidth=0.8, label=f'Oversold (' + str(config_strategy.get("trending", {}).get("rsi_threshold", [30,70])[0]) + ')')
elif strategy_name == "CryptoTradingStrategy":
ax2.axhline(65, color='red', linestyle='--', linewidth=0.8, label='Overbought (65)') # As per Crypto strategy logic
ax2.axhline(35, color='green', linestyle='--', linewidth=0.8, label='Oversold (35)') # As per Crypto strategy logic
2025-05-20 18:28:53 +08:00
# Plot Buy/Sell signals on RSI chart
if not buy_signals.empty and rsi_col_name in buy_signals.columns:
ax2.scatter(buy_signals.index, buy_signals[rsi_col_name], color='green', marker='o', s=20, label=f'Buy Signal ({rsi_col_name})', zorder=5)
if not sell_signals.empty and rsi_col_name in sell_signals.columns:
ax2.scatter(sell_signals.index, sell_signals[rsi_col_name], color='red', marker='o', s=20, label=f'Sell Signal ({rsi_col_name})', zorder=5)
ax2.set_title(f'Relative Strength Index ({rsi_col_name}) with Signals')
ax2.set_ylabel(f'{rsi_col_name} Value')
ax2.set_ylim(0, 100)
2025-05-20 18:28:53 +08:00
ax2.legend()
ax2.grid(True)
else:
logging.info(f"{rsi_col_name} data not available for plotting.")
# Plot 3: Strategy-Specific Indicators
ax3.clear() # Clear previous plot content if any
if strategy_name == "MarketRegimeStrategy":
if 'BBWidth' in processed_data.columns:
sns.lineplot(x=processed_data.index, y='BBWidth', data=processed_data, label='BB Width', ax=ax3)
if 'MarketRegime' in processed_data.columns:
sns.lineplot(x=processed_data.index, y='MarketRegime', data=processed_data, label='Market Regime (Sideways: 1, Trending: 0)', ax=ax3)
ax3.set_title('Bollinger Bands Width & Market Regime')
ax3.set_ylabel('Value')
elif strategy_name == "CryptoTradingStrategy":
if 'VolumeMA_15m' in processed_data.columns:
sns.lineplot(x=processed_data.index, y='VolumeMA_15m', data=processed_data, label='Volume MA (15m)', ax=ax3)
if 'volume' in processed_data.columns: # Plot original volume for comparison
sns.lineplot(x=processed_data.index, y='volume', data=processed_data, label='Volume (15m)', ax=ax3, alpha=0.5)
ax3.set_title('Volume Analysis (15m)')
ax3.set_ylabel('Volume')
ax3.legend()
ax3.grid(True)
plt.xlabel('Date')
fig.tight_layout()
2025-05-20 18:28:53 +08:00
plt.show()
else:
logging.info("No data to plot.")