64 lines
2.4 KiB
Python
64 lines
2.4 KiB
Python
# user_data/strategies/SmartBBGrid.py
|
||
from freqtrade.strategy import IStrategy
|
||
from pandas import DataFrame
|
||
import talib.abstract as ta
|
||
|
||
class SmartBBGrid(IStrategy):
|
||
INTERFACE_VERSION = 3
|
||
timeframe = '4h'
|
||
can_short = False
|
||
|
||
minimal_roi = {"0": 100} # 不自动ROI
|
||
stoploss = -0.99
|
||
startup_candle_count = 200
|
||
use_exit_signal = True
|
||
exit_profit_only = False
|
||
ignore_roi_if_entry_signal = True
|
||
|
||
# ---------- 指标 ----------
|
||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||
# 布林带(20期 2.3倍)
|
||
bb = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.3, nbdevdn=2.3)
|
||
dataframe['bb_lower'] = bb['lowerband']
|
||
dataframe['bb_upper'] = bb['upperband']
|
||
dataframe['bb_mid'] = bb['middleband']
|
||
dataframe['bb_width'] = (dataframe['bb_upper'] - dataframe['bb_lower']) / dataframe['bb_mid']
|
||
|
||
# ADX
|
||
dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)
|
||
return dataframe
|
||
|
||
# ---------- 买入 ----------
|
||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||
dataframe['enter_long'] = False
|
||
|
||
# 震荡或强牛市都允许在下轨补仓
|
||
oscillating = (dataframe['adx'] < 24) & (dataframe['bb_width'] > 0.04)
|
||
strong_bull = dataframe['adx'] > 30
|
||
|
||
dataframe.loc[
|
||
((oscillating | strong_bull) &
|
||
(dataframe['close'] <= dataframe['bb_lower'] * 1.006) &
|
||
(dataframe['volume'] > 0)),
|
||
'enter_long'] = True
|
||
return dataframe
|
||
|
||
# ---------- 卖出 ----------
|
||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||
dataframe['exit_long'] = False
|
||
|
||
# 只有震荡市才卖,牛市死拿
|
||
dataframe.loc[
|
||
(dataframe['adx'] < 24) & (
|
||
(dataframe['close'] >= dataframe['bb_upper'] * 0.994) | # 碰到上轨卖
|
||
(dataframe['close'] >= dataframe['bb_mid'] * 1.13) # 赚13%全清
|
||
),
|
||
'exit_long'] = True
|
||
return dataframe
|
||
|
||
# ---------- 每币25-30个订单 ----------
|
||
def custom_stake_amount(self, **kwargs) -> float:
|
||
total = self.wallets.get_total_stake_amount()
|
||
weights = {'BTC/USDT':0.3, 'ETH/USDT':0.3, 'SOL/USDT':0.4}
|
||
coin = kwargs['pair'].split('/')[0]
|
||
return total * weights.get(coin, 0.33) |