Start to integration strategy

This commit is contained in:
Porter
2025-06-14 13:58:02 +08:00
parent 20a633910d
commit 11f9863e75
3 changed files with 162 additions and 32 deletions
+7 -2
View File
@@ -32,6 +32,7 @@ class ChanLun():
time30 = 30 time30 = 30
time60 = 60 time60 = 60
time4h = 240 time4h = 240
last_peak = {'high': 0, 'low': float('inf')}
def create_all_data(self, dataframe, ticker_indicator): def create_all_data(self, dataframe, ticker_indicator):
all_data = dict() all_data = dict()
all_data['1m'] = dataframe all_data['1m'] = dataframe
@@ -156,8 +157,8 @@ class ChanLun():
else: else:
fx_list.append(0) fx_list.append(0)
klc_strength_list.append(klc.cal_fx_strength(2)) klc_strength_list.append(klc.cal_fx_strength(2))
if klc.klc_fx_type != Chan_KLC_FX.UNKNOWN and klc.cal_fx_strength() > 1: #if klc.klc_fx_type != Chan_KLC_FX.UNKNOWN and klc.cal_fx_strength() > 1:
print(klc.start_time, klc.end_time, klc.cal_fx_strength(), klc.klc_fx_type, fx_list[-1], klc_strength_list[-1]) #print(klc.start_time, klc.end_time, klc.cal_fx_strength(), klc.klc_fx_type, fx_list[-1], klc_strength_list[-1])
else: else:
klc_strength_list.append(0) klc_strength_list.append(0)
fx_list.append(0) fx_list.append(0)
@@ -305,6 +306,10 @@ class ChanLun():
c, c,
v v
] ]
if h > self.last_peak['high']:
self.last_peak['high'] = h
if l < self.last_peak['low']:
self.last_peak['low'] = l
#klu = KLU(self.create_item_dict(item_data, GetColumnNameFromFieldList(fields))) #klu = KLU(self.create_item_dict(item_data, GetColumnNameFromFieldList(fields)))
klu = ChanKLU(time_str, o, h, l, c, v) klu = ChanKLU(time_str, o, h, l, c, v)
klu.set_idx(i) klu.set_idx(i)
+68 -7
View File
@@ -1,7 +1,7 @@
import sys import sys
import os import os
#sys.path.append(os.path.abspath("/Users/jack/Documents/GitHub/chan.py")) sys.path.append(os.path.abspath("/Users/jack/Documents/GitHub/chan.py"))
sys.path.append(os.path.abspath("/Users/jack/Project/chan.py")) #sys.path.append(os.path.abspath("/Users/jack/Project/chan.py"))
from Chan import CChan from Chan import CChan
from BuySellPoint.BS_Point import CBS_Point from BuySellPoint.BS_Point import CBS_Point
from ChanConfig import CChanConfig from ChanConfig import CChanConfig
@@ -193,7 +193,7 @@ class ChanPY():
if bsp_list_pre_len > len(bsp_list): if bsp_list_pre_len > len(bsp_list):
if abs(last_bsp_value) == 1 or abs(last_bsp_value) == 2: if abs(last_bsp_value) == 1 or abs(last_bsp_value) == 2:
bsps.append(1) bsps.append(1)
print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, 98) #print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, 98)
else: else:
bsps.append(99) bsps.append(99)
else: else:
@@ -201,13 +201,13 @@ class ChanPY():
if klu.idx == last_bsp.klu.idx: if klu.idx == last_bsp.klu.idx:
last_bsp_value = self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy) last_bsp_value = self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy)
bsps.append(last_bsp_value) bsps.append(last_bsp_value)
print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value) #print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value)
else: else:
bsps.append(0) bsps.append(0)
else: else:
last_bsp_value = self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy) last_bsp_value = self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy)
bsps.append(last_bsp_value) bsps.append(last_bsp_value)
print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value) #print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value)
else: else:
bsps.append(0) bsps.append(0)
bsp_list_pre_len = len(bsp_list) bsp_list_pre_len = len(bsp_list)
@@ -288,7 +288,68 @@ class ChanPY():
#print(zs.begin.time, zs.end.time) #print(zs.begin.time, zs.end.time)
return bsps, updown, bi_sure return bsps, updown, bi_sure
def get_bsp_state(self, dataframe:DataFrame): def get_bsp_state(self, dataframe:DataFrame):
bsps, updown, bi_sure = self.get_bsps(dataframe) fields = "time,open,high,low,close,volume"
#print(bsps) bsps = []
if self.chanIn:
kl_data = self.get_kl_data(dataframe)
bsp_list = []
bsp_list_pre_len = 0
last_bsp_value = 0
for klu in kl_data: # 获取单根K线
self.chan.trigger_load({self.k_type: [klu]}) # 喂给CChan新增k线
self.last_kline = klu
bsp_list = self.chan.get_bsp()
kl_datas = self.chan.kl_datas[self.k_type]
bi_list = kl_datas.bi_list
lst = kl_datas.lst
if len(bsp_list) > 0:
last_bsp = bsp_list[-1]
#print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, lst[-2].fx, bi_list[-1].dir, bi_list[-1].is_sure,klu.close)
if bsp_list_pre_len > len(bsp_list):
if abs(last_bsp_value) == 1 or abs(last_bsp_value) == 2:
bsps.append(1)
#print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, 98)
else:
bsps.append(99)
else:
if bsp_list_pre_len == len(bsp_list):
if klu.idx == last_bsp.klu.idx:
last_bsp_value = self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy)
bsps.append(last_bsp_value)
#if abs(last_bsp_value) == 1 or abs(last_bsp_value) == 2:
#print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, "Knonw")
else:
bsps.append(0)
else:
last_bsp_value = self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy)
bsps.append(last_bsp_value)
#if abs(last_bsp_value) == 1 or abs(last_bsp_value) == 2:
#print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, "Unknow")
else:
bsps.append(0)
bsp_list_pre_len = len(bsp_list)
self.chanIn = False
else:
klu = CKLine_Unit(self.create_item_dict(self.get_last_item_data(dataframe), GetColumnNameFromFieldList(fields)), autofix=True)
if self.last_kline.time < klu.time:
self.chan.trigger_load({self.k_type: [klu]}) # 喂给CChan新增k线
self.last_kline = klu
bsp_list = self.chan.get_bsp()
last_bsp = bsp_list[-1]
if last_bsp.klu.idx == klu.idx:
bsps.append(self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy))
else:
bsps.append(0)
for index in range(0, len(bsps)):
if not (abs(bsps[index]) == 1 or abs(bsps[index]) == 2):
bsps[index] = 0
else:
if bsps[index] == 2:
bsps[index] = 1
else:
if bsps[index] == -2:
bsps[index] = -1
else:
bsps[index] = 0
return bsps return bsps
+86 -22
View File
@@ -14,7 +14,7 @@ from technical.util import resample_to_interval, resampled_merge
import talib.abstract as ta import talib.abstract as ta
from pandas import DataFrame from pandas import DataFrame
from datetime import datetime, timedelta from datetime import datetime, timedelta
from freqtrade.persistence import Trade from freqtrade.persistence import Trade, Order
from typing import Optional from typing import Optional
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -42,14 +42,14 @@ class ChanLun_BTC_30(IStrategy):
"1200": 0 "1200": 0
} }
# 5m and 15m # 5m and 15m
minimal_roi_1 = { minimal_roi = {
"0": 0.1, "0": 0.1,
"60": 0.05, "60": 0.05,
"120": 0.02, "120": 0.02,
"240": 0 "240": 0
} }
# 15m and 30m # 15m and 30m
minimal_roi_1 = { minimal_roi = {
"0": 0.1, "0": 0.1,
"240": 0.05, "240": 0.05,
"480": 0.03, "480": 0.03,
@@ -62,12 +62,12 @@ class ChanLun_BTC_30(IStrategy):
"3600": 0 "3600": 0
} }
can_short = True can_short = True
lev = 1.0 lev = 2.0
stoploss = -0.3 stoploss = -0.3
trailing_stop = False trailing_stop = True
trailing_stop_positive = 0.025 trailing_stop_positive = 0.025
trailing_stop_positive_offset = 0.045 trailing_stop_positive_offset = 0.045
trailing_only_offset_is_reached = False trailing_only_offset_is_reached = True
position_adjustment_enable = True position_adjustment_enable = True
startup_candle_count = 600 startup_candle_count = 600
@@ -81,6 +81,7 @@ class ChanLun_BTC_30(IStrategy):
chan = ChanLun() chan = ChanLun()
chanpy = ChanPY() chanpy = ChanPY()
classifier = ChanLunClassifier(None) classifier = ChanLunClassifier(None)
last_trade = None
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# resample our dataframes # resample our dataframes
@@ -104,17 +105,13 @@ class ChanLun_BTC_30(IStrategy):
dataframe_4h = self.add_indicators(dataframe_4h) dataframe_4h = self.add_indicators(dataframe_4h)
dataframe_1d = self.add_indicators(dataframe_1d) dataframe_1d = self.add_indicators(dataframe_1d)
#self.chan.plot_dual(dataframe_5, dataframe_30) #self.chan.plot_dual(dataframe_5, dataframe_30)
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
dataframe_5['chanpy_state'] = self.chanpy.get_bsp_state(dataframe_5) dataframe_5['chanpy_state'] = self.chanpy.get_bsp_state(dataframe_5)
state_list, fx_list = self.chan.get_klc_strength_list(dataframe_30) state_list, fx_list = self.chan.get_klc_strength_list(dataframe_30)
dataframe_30['state'] = state_list dataframe_30['state'] = state_list
dataframe_30['fx'] = fx_list dataframe_30['fx'] = fx_list
klc_list = self.chan.get_klc_list(dataframe_30)
bi_list = self.chan.cal_bi_list(klc_list)
if self.last_time + timedelta(minutes=1) < datetime.now(): 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("-------------------------------------------------------------------------------") print("-------------------------------------------------------------------------------")
self.last_time = datetime.now() self.last_time = datetime.now()
dataframe = resampled_merge(dataframe, dataframe_5) dataframe = resampled_merge(dataframe, dataframe_5)
@@ -169,17 +166,83 @@ class ChanLun_BTC_30(IStrategy):
new_exitprice = proposed_rate - 50 new_exitprice = proposed_rate - 50
return new_exitprice return new_exitprice
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
time_in_force: str, current_time: datetime, entry_tag: str | None,
side: str, **kwargs) -> bool:
if self.last_trade:
if self.last_trade.open_date + timedelta(minutes=30) > current_time:
return False
#if self.last_trade:
#print(self.last_trade.open_date, current_time, self.last_trade.open_date + timedelta(minutes=self.time5))
return True
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
current_profit: float, **kwargs):
#dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
#last_candle = dataframe.iloc[-1].squeeze()
"""
# Above 20% profit, sell when rsi < 80
if current_profit > 0.2:
if last_candle["rsi"] < 80:
return "rsi_below_80"
# Between 2% and 10%, sell if EMA-long above EMA-short
if 0.02 < current_profit < 0.1:
if last_candle["emalong"] > last_candle["emashort"]:
return "ema_long_below_80"
# Sell any positions at a loss if they are held for more than one day.
if current_profit < 0.0 and (current_time - trade.open_date_utc).days >= 1:
return "unclog"
"""
if trade.is_short:
last_high = trade.get_custom_data(key="entry_candle_high")
if current_rate > last_high:
print(trade.open_date, last_high, current_rate, "Relay Top FX exit")
return "Relay Top FX exit"
else:
last_low = trade.get_custom_data(key="entry_candle_low")
if current_rate < last_low:
print(trade.open_date, last_low, current_rate, "Relay Bottom FX exit")
return "Relay Bottom FX exit"
def order_filled(self, pair: str, trade: Trade, order: Order, current_time: datetime, **kwargs) -> None:
"""
Called right after an order fills.
Will be called for all order types (entry, exit, stoploss, position adjustment).
:param pair: Pair for trade
:param trade: trade object.
:param order: Order object.
:param current_time: datetime object, containing the current datetime
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
"""
# Obtain pair dataframe (just to show how to access it)
dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
#last_candle = dataframe.iloc[-1].squeeze()
klc_list = self.chan.get_klc_list(resample_to_interval(dataframe, self.get_ticker_indicator() * 30))
bi_list = self.chan.cal_bi_list(klc_list)
last_high = klc_list[-3].high
last_low = klc_list[-3].low
if trade.is_short:
if (trade.nr_of_successful_entries == 1) and (order.ft_order_side == trade.entry_side):
trade.set_custom_data(key="entry_candle_high", value=last_high)
else:
if (trade.nr_of_successful_entries == 1) and (order.ft_order_side == trade.entry_side):
trade.set_custom_data(key="entry_candle_low", value=last_low)
print(trade.open_date, trade.close_date, last_high, last_low, order.ft_order_side, klc_list[-2].start_time, klc_list[-2].end_time)
self.last_trade = trade
return None
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time30) state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time30)
fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time30) fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time30)
chanpy_state_str = 'resample_{}_chanpy_state'.format(self.get_ticker_indicator()*self.time5) chanpy_state_str = 'resample_{}_chanpy_state'.format(self.get_ticker_indicator()*self.time5)
shift_time = self.time30 shift_time = self.time30*2
strength = 2.2
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state'] == "-30") #(dataframe['state'] == "-30")
(dataframe[state_str].shift(shift_time) > 1.0) & (dataframe[state_str].shift(shift_time) > strength) &
(dataframe[fx_str].shift(shift_time) == -1) & (dataframe[fx_str].shift(shift_time) == -1) &
(dataframe[chanpy_state_str].shift(shift_time) == 1) (dataframe[chanpy_state_str].shift(shift_time+10) == 1)
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") & #(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.time30)] == "-10") &
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10")
@@ -189,9 +252,9 @@ class ChanLun_BTC_30(IStrategy):
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state'] == "-30") #(dataframe['state'] == "-30")
(dataframe[state_str].shift(shift_time) > 1.0) & (dataframe[state_str].shift(shift_time) > strength) &
(dataframe[fx_str].shift(shift_time) == 1) & (dataframe[fx_str].shift(shift_time) == 1) &
(dataframe[chanpy_state_str].shift(shift_time) == -1) (dataframe[chanpy_state_str].shift(shift_time+10) == -1)
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") & #(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.time30)] == "-10") &
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10") #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time5)].shift(self.time5) == "-10")
@@ -203,13 +266,14 @@ class ChanLun_BTC_30(IStrategy):
state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time30) state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*self.time30)
fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time30) fx_str = 'resample_{}_fx'.format(self.get_ticker_indicator()*self.time30)
chanpy_state_str = 'resample_{}_chanpy_state'.format(self.get_ticker_indicator()*self.time5) chanpy_state_str = 'resample_{}_chanpy_state'.format(self.get_ticker_indicator()*self.time5)
shift_time = self.time30 shift_time = self.time30*2
strength = 2.2
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state']== "30") #(dataframe['state']== "30")
(dataframe[state_str].shift(shift_time) > 1.0) & (dataframe[state_str].shift(shift_time) > strength) &
(dataframe[fx_str].shift(shift_time) == 1) & (dataframe[fx_str].shift(shift_time) == 1) &
(dataframe[chanpy_state_str].shift(shift_time) == -1) (dataframe[chanpy_state_str].shift(shift_time+10) == -1)
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "10") & #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "10") &
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time60)] == "10") #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time60)] == "10")
), ),
@@ -217,9 +281,9 @@ class ChanLun_BTC_30(IStrategy):
dataframe.loc[ dataframe.loc[
( (
#(dataframe['state']== "30") #(dataframe['state']== "30")
(dataframe[state_str].shift(shift_time) > 1.0) & (dataframe[state_str].shift(shift_time) > strength) &
(dataframe[fx_str].shift(shift_time) == -1) & (dataframe[fx_str].shift(shift_time) == -1) &
(dataframe[chanpy_state_str].shift(shift_time) == 1) (dataframe[chanpy_state_str].shift(shift_time+10) == 1)
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "10") & #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time30)] == "10") &
#(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time60)] == "10") #(dataframe['resample_{}_state'.format(self.get_ticker_indicator()*self.time60)] == "10")
), ),