Professional High-Frequency Scalping Strategy with High Leverage
Timeframe
1m
Direction
Long Only
Stoploss
-1.5%
Trailing Stop
No
ROI
0m: 2.0%, 1m: 1.5%, 3m: 1.0%, 5m: 0.8%
Interface Version
3
Startup Candles
N/A
Indicators
9
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
# --- Do not remove these libs ---
import numpy as np
import pandas as pd
from pandas import DataFrame
from datetime import datetime, timedelta
from typing import Optional, Union
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
IntParameter, IStrategy, merge_informative_pair)
# --------------------------------
# Add your lib to import here
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
class ClaudeScalping(IStrategy):
"""
Professional High-Frequency Scalping Strategy with High Leverage
Optimized for:
- 1-5 minute timeframes
- High leverage (10-20x)
- Low margin requirements
- Quick entries/exits
- Momentum-based scalping
- Tight risk management
- Volume spike detection
- Orderbook analysis
Features:
- Ultra-fast signals with minimal lag
- Scalping-specific indicators (Bollinger Bands, RSI, MACD)
- Volume confirmation for entries
- Tight stops with trailing functionality
- High win rate, low risk/reward ratio approach
- Designed for hyperopt, backtesting, FreqAI and ML
"""
INTERFACE_VERSION = 3
# Scalping-optimized ROI - Quick profits
minimal_roi = {
"0": 0.02, # 2% at any time
"1": 0.015, # 1.5% after 1 minute
"3": 0.01, # 1% after 3 minutes
"5": 0.008, # 0.8% after 5 minutes
"10": 0.005, # 0.5% after 10 minutes
"15": 0.003, # 0.3% after 15 minutes
"30": 0.001 # 0.1% after 30 minutes
}
# Tight stoploss for scalping
stoploss = -0.015 # 1.5% stoploss - tight for high leverage
# Scalping timeframe
timeframe = '1m'
# Informative timeframes for context
inf_5m = '5m'
inf_15m = '15m'
# Process only new candles for speed
process_only_new_candles = True
# Use exit signals
use_exit_signal = True
exit_profit_only = True
ignore_roi_if_entry_signal = False
# Minimal startup candles for speed
startup_candle_count: int = 50
# Strategy parameters - Hyperopt enabled for scalping
# === Momentum Parameters ===
rsi_period = IntParameter(5, 14, default=7, space='buy', optimize=True)
rsi_entry_long = IntParameter(30, 50, default=40, space='buy', optimize=True)
rsi_entry_short = IntParameter(50, 70, default=60, space='sell', optimize=True)
rsi_exit_long = IntParameter(65, 85, default=75, space='sell', optimize=True)
rsi_exit_short = IntParameter(15, 35, default=25, space='sell', optimize=True)
# === Bollinger Bands ===
bb_period = IntParameter(10, 25, default=20, space='buy', optimize=True)
bb_std = DecimalParameter(1.5, 2.5, default=2.0, space='buy', optimize=True)
# === MACD ===
macd_fast = IntParameter(8, 15, default=12, space='buy', optimize=True)
macd_slow = IntParameter(20, 30, default=26, space='buy', optimize=True)
macd_signal = IntParameter(7, 12, default=9, space='buy', optimize=True)
# === EMA ===
ema_fast = IntParameter(5, 12, default=8, space='buy', optimize=True)
ema_slow = IntParameter(15, 25, default=21, space='buy', optimize=True)
# === Volume ===
volume_factor = DecimalParameter(1.2, 3.0, default=2.0, space='buy', optimize=True)
volume_ma_period = IntParameter(5, 20, default=10, space='buy', optimize=True)
# === ADX for trend strength ===
adx_period = IntParameter(10, 20, default=14, space='buy', optimize=True)
adx_threshold = IntParameter(20, 40, default=25, space='buy', optimize=True)
# === Stochastic ===
stoch_k = IntParameter(10, 20, default=14, space='buy', optimize=True)
stoch_d = IntParameter(3, 8, default=3, space='buy', optimize=True)
stoch_smooth = IntParameter(3, 8, default=3, space='buy', optimize=True)
# === Exit Parameters ===
trailing_stop = BooleanParameter(default=True, space='sell', optimize=True)
trailing_stop_positive = DecimalParameter(0.005, 0.02, default=0.01, space='sell', optimize=True)
trailing_stop_positive_offset = DecimalParameter(0.01, 0.03, default=0.015, space='sell', optimize=True)
# === Risk Management ===
max_open_trades = 5
position_adjustment_enable = False # No DCA for scalping
def informative_pairs(self):
"""
Define informative pairs for context
"""
pairs = self.dp.current_whitelist()
informative_pairs = [(pair, self.inf_5m) for pair in pairs]
informative_pairs += [(pair, self.inf_15m) for pair in pairs]
return informative_pairs
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Populate indicators optimized for scalping
"""
# === Price Action ===
dataframe['hl2'] = (dataframe['high'] + dataframe['low']) / 2
dataframe['hlc3'] = (dataframe['high'] + dataframe['low'] + dataframe['close']) / 3
# === EMAs ===
dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=self.ema_fast.value)
dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=self.ema_slow.value)
# === RSI ===
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=self.rsi_period.value)
# === Bollinger Bands ===
bollinger = qtpylib.bollinger_bands(dataframe['close'],
window=self.bb_period.value,
stds=self.bb_std.value)
dataframe['bb_lower'] = bollinger['lower']
dataframe['bb_middle'] = bollinger['mid']
dataframe['bb_upper'] = bollinger['upper']
dataframe['bb_percent'] = ((dataframe['close'] - dataframe['bb_lower']) /
(dataframe['bb_upper'] - dataframe['bb_lower']))
dataframe['bb_width'] = ((dataframe['bb_upper'] - dataframe['bb_lower']) /
dataframe['bb_middle'])
# === MACD ===
macd = ta.MACD(dataframe,
fastperiod=self.macd_fast.value,
slowperiod=self.macd_slow.value,
signalperiod=self.macd_signal.value)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']
# === Stochastic ===
stoch = ta.STOCH(dataframe,
fastk_period=self.stoch_k.value,
slowk_period=self.stoch_d.value,
slowd_period=self.stoch_smooth.value)
dataframe['stoch_k'] = stoch['slowk']
dataframe['stoch_d'] = stoch['slowd']
# === ADX ===
dataframe['adx'] = ta.ADX(dataframe, timeperiod=self.adx_period.value)
dataframe['di_plus'] = ta.PLUS_DI(dataframe, timeperiod=self.adx_period.value)
dataframe['di_minus'] = ta.MINUS_DI(dataframe, timeperiod=self.adx_period.value)
# === Volume Analysis ===
dataframe['volume_sma'] = ta.SMA(dataframe['volume'], timeperiod=self.volume_ma_period.value)
dataframe['volume_ratio'] = dataframe['volume'] / dataframe['volume_sma']
dataframe['high_volume'] = dataframe['volume_ratio'] > self.volume_factor.value
# === VWAP ===
dataframe['vwap'] = qtpylib.vwap(dataframe)
# === ATR for volatility ===
dataframe['atr'] = ta.ATR(dataframe, timeperiod=7) # Shorter period for scalping
# === Price Position Analysis ===
dataframe['close_above_ema_fast'] = dataframe['close'] > dataframe['ema_fast']
dataframe['close_above_ema_slow'] = dataframe['close'] > dataframe['ema_slow']
dataframe['ema_fast_above_slow'] = dataframe['ema_fast'] > dataframe['ema_slow']
# === Scalping-specific indicators ===
dataframe = self.calculate_scalping_signals(dataframe)
# === Higher timeframe context ===
dataframe = self.populate_higher_timeframe_indicators(dataframe, metadata)
return dataframe
def calculate_scalping_signals(self, dataframe: DataFrame) -> DataFrame:
"""
Calculate scalping-specific signals
"""
# Price momentum
dataframe['price_change'] = dataframe['close'].pct_change()
dataframe['price_momentum_3'] = dataframe['close'].pct_change(3)
dataframe['price_momentum_5'] = dataframe['close'].pct_change(5)
# Volume momentum
dataframe['volume_change'] = dataframe['volume'].pct_change()
dataframe['volume_momentum'] = dataframe['volume'].rolling(3).mean() / dataframe['volume'].rolling(10).mean()
# Volatility squeeze
dataframe['squeeze'] = (dataframe['bb_width'] < dataframe['bb_width'].rolling(20).quantile(0.2))
# Support/Resistance levels (simple)
dataframe['resistance'] = dataframe['high'].rolling(10).max()
dataframe['support'] = dataframe['low'].rolling(10).min()
dataframe['near_resistance'] = (dataframe['close'] >= dataframe['resistance'] * 0.998)
dataframe['near_support'] = (dataframe['close'] <= dataframe['support'] * 1.002)
# Candle patterns
dataframe['doji'] = (abs(dataframe['open'] - dataframe['close']) <= (dataframe['high'] - dataframe['low']) * 0.1)
dataframe['hammer'] = (
(dataframe['close'] > dataframe['open']) &
((dataframe['close'] - dataframe['open']) / (0.001 + dataframe['high'] - dataframe['low']) > 0.6) &
((dataframe['open'] - dataframe['low']) / (0.001 + dataframe['high'] - dataframe['low']) > 0.6)
)
return dataframe
def populate_higher_timeframe_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Add higher timeframe context
"""
# 5m context
inf_5m = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_5m)
inf_5m['ema_trend_5m'] = ta.EMA(inf_5m, timeperiod=20)
inf_5m['rsi_5m'] = ta.RSI(inf_5m, timeperiod=14)
inf_5m['trend_5m'] = (inf_5m['close'] > inf_5m['ema_trend_5m']).astype(int)
dataframe = merge_informative_pair(dataframe, inf_5m, self.timeframe, self.inf_5m, ffill=True)
# 15m context
inf_15m = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_15m)
inf_15m['ema_trend_15m'] = ta.EMA(inf_15m, timeperiod=20)
inf_15m['trend_15m'] = (inf_15m['close'] > inf_15m['ema_trend_15m']).astype(int)
dataframe = merge_informative_pair(dataframe, inf_15m, self.timeframe, self.inf_15m, ffill=True)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Scalping entry signals - fast and aggressive
"""
# === LONG CONDITIONS ===
# 1. Trend alignment
trend_bullish = (
(dataframe['ema_fast_above_slow']) &
(dataframe['close_above_ema_fast']) &
(dataframe['trend_5m'] == 1) &
(dataframe['trend_15m'] == 1)
)
# 2. Momentum conditions
momentum_bullish = (
(dataframe['rsi'] > self.rsi_entry_long.value) &
(dataframe['rsi'] < 70) & # Not overbought
(dataframe['macd'] > dataframe['macdsignal']) &
(dataframe['macdhist'] > 0) &
(dataframe['stoch_k'] > 20) &
(dataframe['stoch_k'] < 80)
)
# 3. Price action
price_action_bullish = (
(dataframe['close'] > dataframe['vwap']) &
(dataframe['close'] > dataframe['bb_middle']) &
(dataframe['bb_percent'] > 0.2) & # Not at bottom of BB
(~dataframe['near_resistance']) # Not at resistance
)
# 4. Volume confirmation
volume_bullish = (
(dataframe['high_volume']) &
(dataframe['volume_momentum'] > 1.1) &
(dataframe['volume_change'] > 0)
)
# 5. Volatility and ADX
volatility_ok = (
(dataframe['adx'] > self.adx_threshold.value) & # Strong trend
(dataframe['di_plus'] > dataframe['di_minus']) &
(~dataframe['squeeze']) # Not in squeeze
)
# 6. Entry triggers
entry_triggers = (
(dataframe['price_momentum_3'] > 0.002) | # Recent momentum
(dataframe['hammer']) | # Hammer pattern
(dataframe['close'] > dataframe['bb_middle'].shift(1)) # Breaking BB middle
)
dataframe.loc[
(trend_bullish) &
(momentum_bullish) &
(price_action_bullish) &
(volume_bullish) &
(volatility_ok) &
(entry_triggers),
'enter_long'] = 1
# === SHORT CONDITIONS ===
# 1. Trend alignment
trend_bearish = (
(~dataframe['ema_fast_above_slow']) &
(~dataframe['close_above_ema_fast']) &
(dataframe['trend_5m'] == 0) &
(dataframe['trend_15m'] == 0)
)
# 2. Momentum conditions
momentum_bearish = (
(dataframe['rsi'] < self.rsi_entry_short.value) &
(dataframe['rsi'] > 30) & # Not oversold
(dataframe['macd'] < dataframe['macdsignal']) &
(dataframe['macdhist'] < 0) &
(dataframe['stoch_k'] > 20) &
(dataframe['stoch_k'] < 80)
)
# 3. Price action
price_action_bearish = (
(dataframe['close'] < dataframe['vwap']) &
(dataframe['close'] < dataframe['bb_middle']) &
(dataframe['bb_percent'] < 0.8) & # Not at top of BB
(~dataframe['near_support']) # Not at support
)
# 4. Volume confirmation
volume_bearish = (
(dataframe['high_volume']) &
(dataframe['volume_momentum'] > 1.1) &
(dataframe['volume_change'] > 0)
)
# 5. Volatility and ADX
volatility_ok_short = (
(dataframe['adx'] > self.adx_threshold.value) & # Strong trend
(dataframe['di_minus'] > dataframe['di_plus']) &
(~dataframe['squeeze']) # Not in squeeze
)
# 6. Entry triggers
entry_triggers_short = (
(dataframe['price_momentum_3'] < -0.002) | # Recent negative momentum
(dataframe['close'] < dataframe['bb_middle'].shift(1)) # Breaking BB middle down
)
dataframe.loc[
(trend_bearish) &
(momentum_bearish) &
(price_action_bearish) &
(volume_bearish) &
(volatility_ok_short) &
(entry_triggers_short),
'enter_short'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Scalping exit signals - quick profits
"""
# === EXIT LONG ===
exit_long_conditions = (
(dataframe['rsi'] > self.rsi_exit_long.value) | # Overbought
(dataframe['macd'] < dataframe['macdsignal']) | # MACD cross down
(dataframe['close'] < dataframe['ema_fast']) | # Below fast EMA
(dataframe['stoch_k'] > 80) | # Stochastic overbought
(dataframe['close'] >= dataframe['bb_upper'] * 0.999) | # At BB upper
(dataframe['near_resistance']) | # At resistance
(dataframe['volume_ratio'] < 0.8) # Volume drying up
)
dataframe.loc[exit_long_conditions, 'exit_long'] = 1
# === EXIT SHORT ===
exit_short_conditions = (
(dataframe['rsi'] < self.rsi_exit_short.value) | # Oversold
(dataframe['macd'] > dataframe['macdsignal']) | # MACD cross up
(dataframe['close'] > dataframe['ema_fast']) | # Above fast EMA
(dataframe['stoch_k'] < 20) | # Stochastic oversold
(dataframe['close'] <= dataframe['bb_lower'] * 1.001) | # At BB lower
(dataframe['near_support']) | # At support
(dataframe['volume_ratio'] < 0.8) # Volume drying up
)
dataframe.loc[exit_short_conditions, 'exit_short'] = 1
return dataframe
def leverage(self, pair: str, current_time: datetime, current_rate: float,
proposed_leverage: float, max_leverage: float, entry_tag: Optional[str],
side: str, **kwargs) -> float:
"""
High leverage for scalping
"""
return min(proposed_leverage, 20.0) # Up to 20x leverage
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
"""
Scalping-optimized trailing stop
"""
if not self.trailing_stop.value:
return self.stoploss
# Trailing stop for scalping
if current_profit > self.trailing_stop_positive.value:
return self.trailing_stop_positive_offset.value - current_profit
return self.stoploss
def confirm_trade_entry(self, pair: str, order_type: str, amount: float,
rate: float, time_in_force: str, current_time: datetime,
entry_tag: Optional[str], side: str, **kwargs) -> bool:
"""
Final entry confirmation for scalping
"""
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
# Scalping safety checks
# 1. Ensure decent volume
if last_candle['volume_ratio'] < 1.2:
return False
# 2. Not during low volatility
if last_candle['squeeze']:
return False
# 3. ADX strong enough
if last_candle['adx'] < 20:
return False
return True
def custom_exit(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float,
current_profit: float, **kwargs) -> Optional[Union[str, bool]]:
"""
Custom scalping exits
"""
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
# Quick profit taking
if current_profit > 0.015: # 1.5% profit
return "scalp_profit"
# Volume drying up
if last_candle['volume_ratio'] < 0.6 and current_profit > 0.005:
return "volume_exit"
# Momentum reversal
if trade.is_open:
if (trade.is_short and last_candle['macd'] > last_candle['macdsignal'] and
current_profit > 0.003):
return "momentum_reversal"
elif (not trade.is_short and last_candle['macd'] < last_candle['macdsignal'] and
current_profit > 0.003):
return "momentum_reversal"
return None
def bot_loop_start(self, **kwargs) -> None:
"""
Called at the start of each bot loop
"""
pass
def check_entry_timeout(self, pair: str, trade: 'Trade', order: 'Order',
current_time: datetime, **kwargs) -> bool:
"""
Scalping - cancel entries quickly if not filled
"""
return False
def check_exit_timeout(self, pair: str, trade: 'Trade', order: 'Order',
current_time: datetime, **kwargs) -> bool:
"""
Scalping - cancel exits quickly if not filled
"""
return False