Timeframe
1d
Direction
Long & Short
Stoploss
-1000000.0%
Trailing Stop
No
ROI
N/A
Interface Version
N/A
Startup Candles
30
Indicators
1
freqtrade/freqtrade-strategies
Sample strategy implementing Informative Pairs - compares stake_currency with USDT. Not performing very well - but should serve as an example how to use a referential pair against USDT. author@: xmatthias github@: https://github.com/freqtrade/freqtrade-strategies
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
freqtrade/freqtrade-strategies
from datetime import datetime, timedelta
import talib.abstract as ta
import pandas_ta as pta
from freqtrade.strategy import merge_informative_pair
from freqtrade.persistence import Trade
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
from freqtrade.strategy import DecimalParameter, IntParameter
from functools import reduce
import pandas as pd
import warnings
from freqtrade.exchange import date_minus_candles
import logging
logger = logging.getLogger(__name__)
# 纯山寨币做空策略 策略风险较大,适合大牛市开始回撤时使用 讨论群 https://discord.gg/hfxRh74mK7
'''
dryrun
ROI: Closed trades
∙ 520.179 USDT (67.99%) (26.27 Σ%)
∙ 520.179 USD
ROI: All trades
∙ 454.301 USDT (57.85%) (22.94 Σ%)
∙ 454.301 USD
Total Trade Count: 1129
Bot started: 2025-08-01 09:58:11
First Trade opened: 3 months ago (2025-08-01 10:12:56)
Latest Trade opened: 34 minutes ago (2025-11-03 01:06:45)
Win / Loss: 1060 / 0
Winrate: 100.00%
Expectancy (Ratio): 0.49 (100.00)
Avg. Duration: 3 days, 23:14:35
Best Performing: ATA/USDT:USDT: 7.513 USDT (69.14%)
Trading volume: 31252.268 USDT
Profit factor: inf
Max Drawdown: 0.00% (0 USDT)
from 2025-08-02 10:13:49 (0.554 USDT)
to 2025-08-02 10:13:49 (0.554 USDT)
Monday (count) USDT USD Profit %
---------------- ----------- --------- ----------
2025-11-03 (16) 8.578 USDT 8.58 USD 0.34%
2025-10-27 (129) 73.535 USDT 73.54 USD 3.05%
2025-10-20 (70) 35.088 USDT 35.09 USD 1.48%
2025-10-13 (228) 97.9 USDT 97.90 USD 4.29%
2025-10-06 (119) 75.842 USDT 75.84 USD 3.44%
2025-09-29 (71) 30.198 USDT 30.20 USD 1.39%
2025-09-22 (117) 64.642 USDT 64.64 USD 3.06%
2025-09-15 (41) 16.154 USDT 16.15 USD 0.77%
2025-09-08 (17) 11.559 USDT 11.56 USD 0.56%
2025-09-01 (62) 23.449 USDT 23.45 USD 1.14%
2025-08-25 (48) 19.565 USDT 19.57 USD 0.96%
2025-08-18 (67) 25.629 USDT 25.63 USD 1.27%
2025-08-11 (33) 15.018 USDT 15.02 USD 0.75%
2025-08-04 (33) 15.559 USDT 15.56 USD 0.78%
2025-07-28 (9) 7.466 USDT 7.47 USD 0.38%
2025-07-21 (0) 0 USDT 0.00 USD 0.00%
2025-07-14 (0) 0 USDT 0.00 USD 0.00%
2025-07-07 (0) 0 USDT 0.00 USD 0.00%
2025-06-30 (0) 0 USDT 0.00 USD 0.00%
2025-06-23 (0) 0 USDT 0.00 USD 0.00%
'''
class SL_0707(IStrategy):
can_short = True
timeframe = '1d' #
startup_candle_count = 30 # 需要至少30根K线
process_only_new_candles = True # 只处理新K线
entry_step_pct = -5
entry_stake_amount = 6
num_entry = 300
# 交易参数
stoploss = -10000
use_custom_stoploss = False # 启用动态止损
REAL_USE_MUL = 10
liqutation_ratio = 0.0
def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
current_pair = metadata['pair']
whitelist = self.dp.current_whitelist()
new_cols = {}
for pair in whitelist:
pair_df = self.dp.get_pair_dataframe(pair=pair, timeframe=self.timeframe)
new_cols[f'{pair}_1d_per'] = (pair_df['close'] / pair_df['close'].shift(1)) - 1
# 合并所有新列
new_cols_df = pd.DataFrame(new_cols, index=dataframe.index)
dataframe = pd.concat([dataframe, new_cols_df], axis=1)
# 只保留实际存在的列
valid_cols = [col for col in [f'{pair}_1d_per' for pair in whitelist] if col in dataframe.columns]
current_col = f'{current_pair}_1d_per'
if not valid_cols or current_col not in valid_cols:
dataframe['momentum_rank'] = None
else:
dataframe['momentum_rank'] = dataframe[valid_cols].rank(axis=1, ascending=False)[current_col]
dataframe['ma60'] = ta.SMA(dataframe, timeperiod=60) # 计算60日均线
return dataframe
def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
"""
生成买入信号:
- 做多排名前 2 的币种
- 做空排名后 2 的币种
"""
#dataframe.loc[dataframe['momentum_rank'] <= 2, 'enter_long'] = 1 # 排名前 2 的做多
# 空头条件
enter_short_conditions = [
dataframe['momentum_rank'] <= 10,
dataframe['close'] < dataframe['ma60'],
]
if enter_short_conditions:
dataframe.loc[
reduce(lambda x, y: x & y, enter_short_conditions), ["enter_short", "enter_tag"]
] = (1, "short")
#return dataframe
#dataframe.loc[dataframe['momentum_rank'] >= dataframe['momentum_rank'].max() - 1, 'enter_short'] = 1 # 排名后 2 的做空
return dataframe
def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
dataframe['exit_long'] = 0
dataframe['exit_short'] = 0
return dataframe
def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
current_profit: float, **kwargs):
exit_time = trade.open_date_utc + timedelta(days=1)
exit_time1 = trade.open_date_utc + timedelta(days=100)
exit_time2 = trade.open_date_utc + timedelta(days=200)
if current_time >= exit_time and current_profit > 0.5:
return "profit_50%_time_exit"
if current_time >= exit_time1 and current_profit > 0:
return "time_exit_100day"
#if current_time >= exit_time2 :
# return "time_exit_200day"
open_trades = Trade.get_trades_proxy(is_open=True)
all_profits = {}
total_profit_amount = 0.0
for open_trade in open_trades:
profit_ratio = 0.0
if open_trade.pair == pair:
profit_ratio = current_profit
else:
other_pair = open_trade.pair
(dataframe, _) = self.dp.get_analyzed_dataframe(pair=other_pair, timeframe=self.timeframe)
if not dataframe.empty:
last_candle = dataframe.iloc[-1]
rate_for_other_pair = last_candle['close']
if open_trade.is_short:
# Short position profit ratio
profit_ratio = (1 - (rate_for_other_pair / open_trade.open_rate))
else:
# Long position profit ratio
profit_ratio = ((rate_for_other_pair / open_trade.open_rate) - 1)
profit_ratio *= open_trade.leverage
profit_pct = profit_ratio * 100
profit_amount = open_trade.stake_amount * profit_ratio
total_profit_amount += profit_amount
all_profits[open_trade.pair] = f"{profit_pct:.2f}% ({profit_amount:.2f} {open_trade.stake_currency})"
ratio = total_profit_amount / self.wallets.get_total('USDT')
if ratio < -1:
logger.warning(f"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.")
logger.warning(f"Total profit ratio is too low!!!!!!liqutation_ratio!!!!!!!!: {ratio:.2%}.")
logger.warning(f"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.")
return None
self.liqutation_ratio = ratio
if pair == open_trades[0].pair:
#logger.info(f"--- Backtest time: {current_time} ---")
#logger.info(f"Current profit for all open trades: {all_profits}")
#logger.info(f"Total profit amount for all open trades: {total_profit_amount:.2f} USDT")
logger.info(f"Total profit ratio: {ratio:.2%}")
#logger.info(f"trade number:{len(all_profits)}")
#logger.info("---------------------------------")
return None
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
proposed_stake: float, min_stake: float | None, max_stake: float,
leverage: float, entry_tag: str | None, side: str,
**kwargs) -> float:
#logger.info(f"Calculating custom stake amount for {pair} at {current_time}: self.entry_stake_amount={self.entry_stake_amount}")
return self.entry_stake_amount / self.REAL_USE_MUL
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
time_in_force: str, side: str, **kwargs) -> bool:
if self.liqutation_ratio < -0.5:
logger.warning(f"Liquidity ratio is too low ({self.liqutation_ratio}), skipping trade entry for {pair}.")
return False
logger.info(f"Confirming trade entry for {pair}: order_type={order_type}, amount={amount}, rate={rate}, side={side}")
return True
position_adjustment_enable = True
def adjust_trade_position(self, trade: Trade, current_time: datetime,current_rate: float, current_profit: float,min_stake: float | None, max_stake: float,
current_entry_rate: float, current_exit_rate: float,current_entry_profit: float, current_exit_profit: float,**kwargs
) -> float | None | tuple[float | None, str | None]:
current_profit_stake = current_profit * trade.stake_amount
current_profit_stake_ratio = current_profit_stake / self.wallets.get_total('USDT')
#logger.info(f"Adjusting position for {trade.pair} at {current_time}: current_profit={current_profit},trade.stake_amount={trade.stake_amount} current_profit_stake={current_profit_stake} current_profit_stake_ratio = {current_profit_stake_ratio}")
last_time = trade.date_last_filled_utc + timedelta(days=7)
if self.wallets:
free_eth = 0.95*self.wallets.get_free('USDT')
used_eth = self.wallets.get_used('USDT')
total_eth = self.wallets.get_total('USDT')
ratio = self.wallets.get_free('USDT') / self.wallets.get_total('USDT')
#logger.info(f"Free USDT: {free_eth}, Used USDT: {used_eth}, Total USDT: {total_eth}")
if trade.nr_of_successful_entries == 1:
self.entry_stake_amount = max(6, free_eth / self.num_entry)
#self.entry_stake_amount = 6
#logger.info(f"Adjusting entry stake amount to {self.entry_stake_amount} USDT based on available balance.,Free USDT: {free_eth}")
if current_profit < self.entry_step_pct and trade.nr_of_successful_entries != self.num_entry and current_time > last_time and current_profit_stake_ratio > -0.05 :
#logger.info(f"Adjusting position for {trade.pair} at {current_time}: current_profit={current_profit}, nr_of_successful_entries={trade.nr_of_successful_entries}")
if trade.nr_of_successful_entries < self.num_entry:
logger.info(f"Adjusting position for {trade.pair} at {current_time}: current_profit={current_profit}, nr_of_successful_entries={trade.nr_of_successful_entries}, entry_stake_amount={self.entry_stake_amount}")
return self.entry_stake_amount / self.REAL_USE_MUL
return None
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
rate: float, time_in_force: str, exit_reason: str,
exit_tag: str = None, **kwargs) -> bool:
#logger.info(f"exit-----------------------------------------------------------------------------exit")
if self.wallets:
free_usdt = 0.95*self.wallets.get_free('USDT')
used_usdt = self.wallets.get_used('USDT')
total_usdt = self.wallets.get_total('USDT')
logger.info(f"Confirming trade exit for {pair}: order_type={order_type}, amount={amount}, rate={rate}, exit_reason={exit_reason}, free_usdt: {free_usdt}, used_usdt: {used_usdt}, total_usdt: {total_usdt}")
return True
def leverage(self, pair: str, current_time: datetime, current_rate: float,
proposed_leverage: float, max_leverage: float, entry_tag: str, side: str,
**kwargs) -> float:
return 20