Debug version to see what's happening with signals
Timeframe
5m
Direction
Long Only
Stoploss
-8.0%
Trailing Stop
No
ROI
0m: 15.0%, 30m: 8.0%, 60m: 4.0%, 120m: 0.0%
Interface Version
N/A
Startup Candles
N/A
Indicators
4
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
# Enhanced Perp-Spot Basis Trading Strategy with Debug
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np
import pandas as pd
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
from freqtrade.strategy import (BooleanParameter, CategoricalParameter,
DecimalParameter, IntParameter, RealParameter)
import talib.abstract as ta
import pandas_ta as pta
from typing import Dict, List, Optional
from datetime import datetime
import logging
logger = logging.getLogger(__name__)
class PerpSpotBasisStrategy_DebugV2(IStrategy):
"""
Debug version to see what's happening with signals
"""
INTERFACE_VERSION: int = 3
# Timeframe
timeframe = "5m"
# ROI table - take profits at different time intervals
minimal_roi = {
"0": 0.15, # 15% at any time
"30": 0.08, # 8% after 30 minutes
"60": 0.04, # 4% after 1 hour
"120": 0 # 0% (hold) after 2 hours
}
# Stop loss
stoploss = -0.08 # 8% stop loss
# Process only new candles
process_only_new_candles = True
# FreqAI configuration
freqai_label_period = 12
freqai_min_return = 0.003
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Basic indicators
dataframe['rsi'] = ta.RSI(dataframe)
dataframe['adx'] = ta.ADX(dataframe)
# Bollinger Bands
bollinger = qtpylib.bollinger_bands(dataframe['close'], window=20, stds=2)
dataframe['bb_lowerband'] = bollinger['lower']
dataframe['bb_middleband'] = bollinger['mid']
dataframe['bb_upperband'] = bollinger['upper']
dataframe['bb_width'] = dataframe['bb_upperband'] - dataframe['bb_lowerband']
# MACD
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macd_signal'] = macd['macdsignal']
dataframe['macd_hist'] = macd['macdhist']
# Volume analysis
dataframe['volume_sma'] = dataframe['volume'].rolling(window=20).mean()
# Try to load futures data for basis calculation
try:
futures_data = self.dp.get_pair_dataframe(
pair=f"{metadata['pair'].split('/')[0]}/USDT:USDT", # BTC/USDT -> BTC/USDT:USDT
timeframe=self.timeframe
)
if len(futures_data) > 0:
# Merge by timestamp
merged = pd.merge(dataframe.reset_index(), futures_data[['date', 'close']].rename(columns={'close': 'futures_close'}),
on='date', how='left')
# Calculate basis
basis = (merged['close'] - merged['futures_close']) / merged['futures_close'] * 100
dataframe['basis'] = basis.values
# Calculate basis statistics
dataframe['basis_ma'] = dataframe['basis'].rolling(20).mean()
dataframe['basis_std'] = dataframe['basis'].rolling(20).std()
dataframe['basis_zscore'] = (dataframe['basis'] - dataframe['basis_ma']) / dataframe['basis_std']
logger.info(f"Loaded futures data for {metadata['pair']} - basis calculated")
else:
dataframe['basis'] = 0
dataframe['basis_ma'] = 0
dataframe['basis_std'] = 1
dataframe['basis_zscore'] = 0
logger.warning(f"No futures data for {metadata['pair']}")
except Exception as e:
logger.error(f"Error loading futures data for {metadata['pair']}: {e}")
dataframe['basis'] = 0
dataframe['basis_ma'] = 0
dataframe['basis_std'] = 1
dataframe['basis_zscore'] = 0
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Very simple entry conditions for debugging
conditions = [
dataframe['volume'] > 0, # Basic volume filter
]
# Simple RSI oversold condition
basic_condition = dataframe['rsi'] < 40
dataframe.loc[
basic_condition &
(dataframe['volume'] > 0),
'enter_long'
] = 1
# Count signals for debugging
total_signals = dataframe['enter_long'].sum()
logger.info(f"{metadata['pair']}: Generated {total_signals} entry signals")
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Simple exit conditions
dataframe.loc[
dataframe['rsi'] > 60,
'exit_long'
] = 1
return dataframe
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
"""Set FreqAI targets with simple logic"""
# Calculate future returns
future_return = dataframe["close"].shift(-self.freqai_label_period) / dataframe["close"] - 1
# Simple labeling
dataframe["&-enter_long"] = np.where(
future_return > self.freqai_min_return,
"enter",
"hold"
)
dataframe["&-enter_long"] = dataframe["&-enter_long"].fillna("hold")
return dataframe
# FreqAI configuration - match config.json identifier
freqai_info = {
"identifier": "MyFreqAIModel_Enhanced",
"features": [
"%-rsi", "%-adx", "%-bb_width", "%-macd",
"%-basis", "%-basis_zscore", "%-volume_sma"
],
"label_period_candles": freqai_label_period,
"data_split_parameters": {"test_size": 0.2, "shuffle": False},
"model_training_parameters": {
"n_estimators": 50,
"max_depth": 5,
"random_state": 42,
"n_jobs": -1
}
}