Add new strategy files
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"$schema": "https://schema.freqtrade.io/schema.json",
|
||||
"max_open_trades": 1,
|
||||
"stake_currency": "USDT",
|
||||
"stake_amount": "unlimited",
|
||||
"tradable_balance_ratio": 0.99,
|
||||
"fiat_display_currency": "USD",
|
||||
"dry_run": false,
|
||||
"db_url": "sqlite:///tradesv3.chanlun_btc_15.sqlite",
|
||||
"dry_run_wallet": 1000,
|
||||
"cancel_open_orders_on_exit": true,
|
||||
"trading_mode": "futures",
|
||||
"margin_mode": "isolated",
|
||||
"can_short" : true,
|
||||
"timeframe" : "1m",
|
||||
"process_only_new_candles" : false,
|
||||
"unfilledtimeout": {
|
||||
"entry": 1,
|
||||
"exit": 1,
|
||||
"exit_timeout_count": 5,
|
||||
"unit": "minutes"
|
||||
},
|
||||
"entry_pricing": {
|
||||
"price_side": "same",
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1,
|
||||
"price_last_balance": 0.0,
|
||||
"check_depth_of_market": {
|
||||
"enabled": false,
|
||||
"bids_to_ask_delta": 1
|
||||
}
|
||||
},
|
||||
"exit_pricing":{
|
||||
"price_side": "same",
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1
|
||||
},
|
||||
"exchange": {
|
||||
"name": "binance",
|
||||
"key": "hvoXanRExQvcN4tyGFvEnsSF4gqxXp6ZJnBu5lnhvlVuHaDbj2PhLBQGCLkkyeI8",
|
||||
"secret": "3UKA2oyDj7OoXrausmnaLwLlNfXmlNf2imBdmQqqKHArcJfk6X9xjaUF19wzu82l",
|
||||
"ccxt_config": {},
|
||||
"ccxt_async_config": {},
|
||||
"pair_whitelist": [
|
||||
"BTC/USDT:USDT"
|
||||
],
|
||||
"pair_blacklist": [
|
||||
"BNB/.*"
|
||||
]
|
||||
},
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "StaticPairList",
|
||||
"number_assets": 1,
|
||||
"sort_key": "quoteVolume",
|
||||
"min_value": 0,
|
||||
"refresh_period": 1800
|
||||
}
|
||||
],
|
||||
"telegram": {
|
||||
"enabled": true,
|
||||
"token": "7677670958:AAFL_jgZvNUTPR3R3vWieREX_tDVi9w2C1Y",
|
||||
"chat_id": "580807463"
|
||||
},
|
||||
"api_server": {
|
||||
"enabled": false,
|
||||
"listen_ip_address": "127.0.0.1",
|
||||
"listen_port": 8811,
|
||||
"verbosity": "error",
|
||||
"enable_openapi": false,
|
||||
"jwt_secret_key": "14d3510740e2c39a973a8895f1aa2704d98d08b86170260085709fa5ea48251d",
|
||||
"ws_token": "dtKKDnafBrX4icq_ZCw7acJTahTK4h_yvg",
|
||||
"CORS_origins": [],
|
||||
"username": "freqtrader",
|
||||
"password": "FreqTrade007"
|
||||
},
|
||||
"bot_name": "freqtrade",
|
||||
"initial_state": "running",
|
||||
"force_entry_enable": false,
|
||||
"internals": {
|
||||
"process_throttle_secs": 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
# --- Do not remove these libs ---
|
||||
from statistics import median
|
||||
from freqtrade.strategy import IStrategy
|
||||
import sys
|
||||
import os
|
||||
# 添加父目录到系统路径
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
from ChanLun import ChanLun
|
||||
from ChanLun_Classifier import ChanLunClassifier
|
||||
from ChanEnum import Chan_FX_TYPE, Chan_KLC_FX, Chan_BI_DIR, Chan_KLC_FX
|
||||
# --------------------------------
|
||||
from technical.util import resample_to_interval, resampled_merge
|
||||
import talib.abstract as ta
|
||||
from pandas import DataFrame
|
||||
from datetime import datetime, timedelta
|
||||
from freqtrade.persistence import Trade
|
||||
from typing import Optional
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
### Now you can use logger.info('asfd') to log
|
||||
# freqtrade plot-dataframe --strategy ChanLun_BTC_15 --datadir user_data/data/binance -c ./user_data/ChanLun_SOL_15.json --timerange=20250309-
|
||||
|
||||
# freqtrade trade -c ./user_data/Chan/config/ChanLun_BTC_15.json --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies
|
||||
# freqtrade backtesting -c ./user_data/Chan/config/ChanLun_BTC_15.json --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies --timerange=20250416-
|
||||
# freqtrade download-data -c ./user_data/Chan/config/ChanLun_BTC_15.json -t 1m --pairs BTC/USDT:USDT --timerange=20250405-
|
||||
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --spaces roi stoploss --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies -c ./user_data/Chan/config/ChanLun_BTC_15.json -e 200 --timerange=20250201-20250401
|
||||
|
||||
# sudo docker compose run --rm chan_btc backtesting -c ./user_data/Chan/config/ChanLun_SOL.json --strategy ChanLun_SOL --strategy-path ./user_data/Chan/strategies --timerange=20250101-
|
||||
# sudo docker compose run --rm chan_btc download-data -c ./user_data/Chan/config/ChanLun_BTC_15.json --pairs BTC/USDT:USDT -t 1m --timerange 20240101-
|
||||
# sudo docker compose run --rm chan_btc trade -c ./user_data/Chan/config/ChanLun_BTC_15.json --strategy ChanLun_BTC_15 --strategy-path ./user_data/Chan/strategies
|
||||
|
||||
class ChanLun_BTC_15(IStrategy):
|
||||
INTERFACE_VERSION: int = 3
|
||||
# Minimal ROI designed for the strategy.
|
||||
# This attribute will be overridden if the config file contains "minimal_roi"
|
||||
# 30m and 1h
|
||||
minimal_roi = {
|
||||
"0": 0.30,
|
||||
"360": 0.2,
|
||||
"640": 0.1,
|
||||
"1200": 0
|
||||
}
|
||||
# 5m and 15m
|
||||
minimal_roi_1 = {
|
||||
"0": 0.1,
|
||||
"60": 0.05,
|
||||
"120": 0.02,
|
||||
"240": 0
|
||||
}
|
||||
# 15m and 30m
|
||||
minimal_roi_1 = {
|
||||
"0": 0.1,
|
||||
"240": 0.05,
|
||||
"480": 0.03,
|
||||
"600": 0
|
||||
}
|
||||
minimal_roi_2 = {
|
||||
"0": 0.10,
|
||||
"1200": 0.05,
|
||||
"2400": 0.025,
|
||||
"3600": 0
|
||||
}
|
||||
can_short = True
|
||||
lev = 20.0
|
||||
stoploss = -0.3
|
||||
trailing_stop = False
|
||||
trailing_stop_positive = 0.025
|
||||
trailing_stop_positive_offset = 0.045
|
||||
trailing_only_offset_is_reached = False
|
||||
|
||||
position_adjustment_enable = True
|
||||
startup_candle_count = 600
|
||||
|
||||
time5 = 5
|
||||
time15 = 15
|
||||
time30 = 30
|
||||
time60 = 60
|
||||
time4h = 240
|
||||
time5 = 15
|
||||
last_time = datetime.now()
|
||||
chan = ChanLun()
|
||||
classifier = ChanLunClassifier(None)
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
# resample our dataframes
|
||||
dataframe_5 = resample_to_interval(dataframe, self.get_ticker_indicator() * 5)
|
||||
dataframe_15 = resample_to_interval(dataframe, self.get_ticker_indicator() * 15)
|
||||
dataframe_30 = resample_to_interval(dataframe, self.get_ticker_indicator() * 30)
|
||||
dataframe_60 = resample_to_interval(dataframe, self.get_ticker_indicator() * 60)
|
||||
dataframe_4h = resample_to_interval(dataframe, self.get_ticker_indicator() * 240)
|
||||
|
||||
#dataframe_1d = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1d')
|
||||
#dataframe_1w = resample_to_interval(dataframe_1d, self.get_ticker_indicator() * 10080)
|
||||
#dataframe_1m = resample_to_interval(dataframe_1d, self.get_ticker_indicator() * 43200)
|
||||
|
||||
dataframe_1d = resample_to_interval(dataframe, self.get_ticker_indicator() * 1440)
|
||||
#dataframe_1w = resample_to_interval(dataframe, self.get_ticker_indicator() * 10080)
|
||||
#dataframe_1m = resample_to_interval(dataframe, self.get_ticker_indicator() * 43200)
|
||||
dataframe = self.add_indicators(dataframe)
|
||||
dataframe_5 = self.add_indicators(dataframe_5)
|
||||
dataframe_30 = self.add_indicators(dataframe_30)
|
||||
dataframe_60 = self.add_indicators(dataframe_60)
|
||||
dataframe_4h = self.add_indicators(dataframe_4h)
|
||||
dataframe_1d = self.add_indicators(dataframe_1d)
|
||||
#self.chan.plot_dual(dataframe_5, dataframe_30)
|
||||
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
|
||||
|
||||
state_list, fx_list = self.chan.get_klc_strength_list(dataframe_15)
|
||||
dataframe_15['state'] = state_list
|
||||
dataframe_15['fx'] = fx_list
|
||||
klc_list = self.chan.get_klc_list(dataframe_15)
|
||||
bi_list = self.chan.cal_bi_list(klc_list)
|
||||
if self.last_time + timedelta(minutes=1) < datetime.now():
|
||||
print(state_list[-1], state_list[-2], state_list[-3], state_list[-4], state_list[-5])
|
||||
print(fx_list[-1], fx_list[-2], fx_list[-3], fx_list[-4], fx_list[-5])
|
||||
print(klc_list[-1].klc_fx_type, klc_list[-2].klc_fx_type, klc_list[-3].klc_fx_type, klc_list[-4].klc_fx_type, klc_list[-5].klc_fx_type)
|
||||
print("-------------------------------------------------------------------------------")
|
||||
self.last_time = datetime.now()
|
||||
#dataframe = resampled_merge(dataframe, dataframe_5)
|
||||
dataframe = resampled_merge(dataframe, dataframe_15)
|
||||
#dataframe = resampled_merge(dataframe, dataframe_30)
|
||||
#dataframe = resampled_merge(dataframe, dataframe_60)
|
||||
#dataframe = resampled_merge(dataframe, dataframe_4h)
|
||||
return dataframe
|
||||
|
||||
def add_indicators(self, df):
|
||||
fast = 8
|
||||
slow = 16
|
||||
period = 6
|
||||
macd = ta.MACD(df, fastperiod=fast, slowperiod=slow, signalperiod=period)
|
||||
df['macd'] = macd['macd']
|
||||
df['macdsignal'] = macd['macdsignal']
|
||||
df['macdhist'] = macd['macdhist']
|
||||
df['ma5'] = ta.MA(df, timeperiod=5)
|
||||
df['ma10'] = ta.MA(df, timeperiod=10)
|
||||
df['ma30'] = ta.EMA(df, timeperiod=30)
|
||||
df['ma250'] = ta.MA(df, timeperiod=250)
|
||||
df['rsi'] = ta.RSI(df, timeperiod=14)
|
||||
df['volume_ratio'] = self.cal_volume_ratio(df)
|
||||
return df
|
||||
def cal_volume_ratio(self, dataframe, window=10):
|
||||
df = dataframe.copy()
|
||||
# 计算过去N根K线的平均成交量
|
||||
df['avg_volume'] = df['volume'].rolling(window=window).mean()
|
||||
# 计算量比
|
||||
df['volume_ratio'] = df['volume'] / df['avg_volume']
|
||||
# 填充缺失值(前N根K线)
|
||||
df['volume_ratio'] = df['volume_ratio'].fillna(1.0)
|
||||
return df['volume_ratio']
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time5)
|
||||
fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time5)
|
||||
dataframe.loc[
|
||||
(
|
||||
#(dataframe['state'] == "-30")
|
||||
(dataframe[state_str].shift(self.time5*2) > 1.0) &
|
||||
(dataframe[fx_str].shift(self.time5*2) == -1)
|
||||
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") &
|
||||
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "-10") &
|
||||
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10")
|
||||
#(qtpylib.crossed_above(dataframe['macd'], dataframe['macdsignal']))
|
||||
),
|
||||
['enter_long', 'enter_tag']] = (1, 'long_signal_chan')
|
||||
dataframe.loc[
|
||||
(
|
||||
#(dataframe['state'] == "-30")
|
||||
(dataframe[state_str].shift(self.time5*2) > 1.0) &
|
||||
(dataframe[fx_str].shift(self.time5*2) == 1)
|
||||
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") &
|
||||
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "-10") &
|
||||
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10")
|
||||
#(qtpylib.crossed_above(dataframe['macd'], dataframe['macdsignal']))
|
||||
),
|
||||
['enter_short', 'enter_tag']] = (1, 'short_signal_chan')
|
||||
return dataframe
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time5)
|
||||
fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time5)
|
||||
dataframe.loc[
|
||||
(
|
||||
#(dataframe['state']== "30")
|
||||
(dataframe[state_str].shift(self.time5*2) > 1.0) &
|
||||
(dataframe[fx_str].shift(self.time5*2) == 1)
|
||||
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "10") &
|
||||
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time60)] == "10")
|
||||
),
|
||||
['exit_long', 'exit_tag']] = (1, 'long_close_signal_chan')
|
||||
dataframe.loc[
|
||||
(
|
||||
#(dataframe['state']== "30")
|
||||
(dataframe[state_str].shift(self.time5*2) > 1.0) &
|
||||
(dataframe[fx_str].shift(self.time5*2) == -1)
|
||||
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "10") &
|
||||
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time60)] == "10")
|
||||
),
|
||||
['exit_short', 'exit_tag']] = (1, 'short_close_signal_chan')
|
||||
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:
|
||||
return self.lev
|
||||
|
||||
def get_ticker_indicator(self):
|
||||
return int(self.timeframe[:-1])
|
||||
Reference in New Issue
Block a user