403 lines
12 KiB
Python
403 lines
12 KiB
Python
import sys
|
|
import os
|
|
#sys.path.append(os.path.abspath("/Users/jack/Documents/GitHub/chan.py"))
|
|
sys.path.append(os.path.abspath("/Users/jack/Project/chan.py"))
|
|
from Chan import CChan
|
|
from BuySellPoint.BS_Point import CBS_Point
|
|
from ChanConfig import CChanConfig
|
|
from Common.CEnum import AUTYPE, DATA_SRC, KL_TYPE, DATA_FIELD, BSP_TYPE, FX_TYPE, BI_DIR, KLINE_DIR, SEG_DIR
|
|
from KLine.KLine_Unit import CKLine_Unit
|
|
from Common.CTime import CTime
|
|
from Common.func_util import kltype_lt_day, str2float
|
|
from Bi.Bi import CBi
|
|
from typing import Dict, List
|
|
from functools import reduce
|
|
from pandas import DataFrame
|
|
from datetime import datetime, timedelta, timezone
|
|
|
|
|
|
def GetColumnNameFromFieldList(fileds: str):
|
|
_dict = {
|
|
"time": DATA_FIELD.FIELD_TIME,
|
|
"open": DATA_FIELD.FIELD_OPEN,
|
|
"high": DATA_FIELD.FIELD_HIGH,
|
|
"low": DATA_FIELD.FIELD_LOW,
|
|
"close": DATA_FIELD.FIELD_CLOSE,
|
|
"volume": DATA_FIELD.FIELD_VOLUME
|
|
}
|
|
return [_dict[x] for x in fileds.split(",")]
|
|
class ChanPY():
|
|
k_type = KL_TYPE.K_5M
|
|
config = CChanConfig({
|
|
"bi_strict": True,
|
|
"bi_algo": "normal",
|
|
"trigger_step": True,
|
|
"skip_step": 0,
|
|
"divergence_rate": float("inf"),
|
|
"bsp2_follow_1": False,
|
|
"bsp3_follow_1": False,
|
|
"min_zs_cnt": 0,
|
|
"bs1_peak": False,
|
|
"macd_algo": "peak",
|
|
"bs_type": '1,2,3a,1p,2s,3b',
|
|
"print_warning": True,
|
|
"zs_algo": "normal",
|
|
})
|
|
chan = CChan(
|
|
code="BTC/USDT:USDT",
|
|
data_src=DATA_SRC.CCXT,
|
|
lv_list=[k_type],
|
|
config=config,
|
|
autype=AUTYPE.QFQ,
|
|
)
|
|
klu_list = []
|
|
bsps = []
|
|
chanIn = True
|
|
#def __init__(self, dataframe):
|
|
#self.klu_list = self.get_kl_data(dataframe)
|
|
#for klu in self.klu_list:
|
|
#self.chan.trigger_load({self.k_type: [klu]})
|
|
def add_klu(self, klu):
|
|
if klu:
|
|
self.chan.trigger_load({self.k_type: [klu]})
|
|
self.klu_list.append(klu)
|
|
def add_klu_from_dataframe(self, dataframe):
|
|
if len(dataframe) > len(self.klu_list) and len(dataframe) - len(self.klu_list) == 1:
|
|
klu = self.get_last_klu(dataframe)
|
|
self.chan.trigger_load({self.k_type: [klu]})
|
|
self.klu_list.append(klu)
|
|
def parse_time_column(self, inp):
|
|
if len(inp) == 10:
|
|
year = int(inp[:4])
|
|
month = int(inp[5:7])
|
|
day = int(inp[8:10])
|
|
hour = minute = 0
|
|
elif len(inp) == 17:
|
|
year = int(inp[:4])
|
|
month = int(inp[4:6])
|
|
day = int(inp[6:8])
|
|
hour = int(inp[8:10])
|
|
minute = int(inp[10:12])
|
|
elif len(inp) == 19:
|
|
year = int(inp[:4])
|
|
month = int(inp[5:7])
|
|
day = int(inp[8:10])
|
|
hour = int(inp[11:13])
|
|
minute = int(inp[14:16])
|
|
else:
|
|
raise Exception(f"unknown time column from TradingView:{inp}")
|
|
return CTime(year, month, day, hour, minute, auto=not kltype_lt_day(self.k_type))
|
|
|
|
def create_item_dict(self, data, column_name):
|
|
for i in range(len(data)):
|
|
data[i] = self.parse_time_column(data[i]) if i == 0 else str2float(data[i])
|
|
return dict(zip(column_name, data))
|
|
def get_last_klu(self, dataframe:DataFrame):
|
|
fields = "time,open,high,low,close,volume"
|
|
item = dataframe.iloc[-1]
|
|
date = item['date']
|
|
o = item['open']
|
|
h = item['high']
|
|
l = item['low']
|
|
c = item['close']
|
|
v = item['volume']
|
|
#time_obj = date.fromtimestamp(date)
|
|
time_str = date.strftime('%Y-%m-%d %H:%M:%S')
|
|
item_data = [
|
|
time_str,
|
|
o,
|
|
h,
|
|
l,
|
|
c,
|
|
v
|
|
]
|
|
klu = CKLine_Unit(self.create_item_dict(item_data, GetColumnNameFromFieldList(fields)), autofix=True)
|
|
klu.set_idx(len(dataframe)-1)
|
|
return klu
|
|
def get_kl_data(self, dataframe:DataFrame):
|
|
fields = "time,open,high,low,close,volume"
|
|
klu_list = []
|
|
for i in range(0, len(dataframe)):
|
|
item = dataframe.iloc[i]
|
|
date = item['date']
|
|
o = item['open']
|
|
h = item['high']
|
|
l = item['low']
|
|
c = item['close']
|
|
v = item['volume']
|
|
#time_obj = date.fromtimestamp(date)
|
|
time_str = date.strftime('%Y-%m-%d %H:%M:%S')
|
|
item_data = [
|
|
time_str,
|
|
o,
|
|
h,
|
|
l,
|
|
c,
|
|
v
|
|
]
|
|
klu = CKLine_Unit(self.create_item_dict(item_data, GetColumnNameFromFieldList(fields)), autofix=True)
|
|
klu.set_idx(i)
|
|
klu_list.append(klu)
|
|
return klu_list
|
|
def get_bsp_type(self, bsp_type, is_buy):
|
|
if is_buy:
|
|
if bsp_type == BSP_TYPE.T1:
|
|
return 1
|
|
if bsp_type == BSP_TYPE.T1P:
|
|
return 2
|
|
if bsp_type == BSP_TYPE.T2:
|
|
return 3
|
|
if bsp_type == BSP_TYPE.T2S:
|
|
return 4
|
|
if bsp_type == BSP_TYPE.T3A:
|
|
return 5
|
|
if bsp_type == BSP_TYPE.T3B:
|
|
return 6
|
|
else:
|
|
if bsp_type == BSP_TYPE.T1:
|
|
return -1
|
|
if bsp_type == BSP_TYPE.T1P:
|
|
return -2
|
|
if bsp_type == BSP_TYPE.T2:
|
|
return -3
|
|
if bsp_type == BSP_TYPE.T2S:
|
|
return -4
|
|
if bsp_type == BSP_TYPE.T3A:
|
|
return -5
|
|
if bsp_type == BSP_TYPE.T3B:
|
|
return -6
|
|
def get_bsps(self, dataframe:DataFrame):
|
|
fields = "time,open,high,low,close,volume"
|
|
bsps = []
|
|
updown = []
|
|
bi_sure = []
|
|
if self.chanIn:
|
|
kl_data = self.get_kl_data(dataframe)
|
|
bsp_list = []
|
|
bsp_list_pre_len = 0
|
|
last_bsp_value = 0
|
|
last_updown = -1
|
|
bi_list_pre_len = 0
|
|
pre_bi = None
|
|
zs_list_pre_len = 0
|
|
pre_zs = None
|
|
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)
|
|
#print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value)
|
|
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)
|
|
#print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value)
|
|
else:
|
|
bsps.append(0)
|
|
bsp_list_pre_len = len(bsp_list)
|
|
|
|
#Check zs -----------------------------------
|
|
zs_list = kl_datas.zs_list
|
|
if len(zs_list) > 0:
|
|
zs = zs_list[-1]
|
|
#if zs_list_pre_len > len(zs_list):
|
|
#print("No zs", zs.begin.time)
|
|
#if len(zs_list) > zs_list_pre_len:
|
|
#print(zs.begin.time, zs.end.time, zs.end.idx, zs.high, zs.low, zs.peak_high, zs.peak_low)
|
|
zs_list_pre_len = len(zs_list)
|
|
pre_zs = zs
|
|
|
|
#Check Bi -----------------------------------
|
|
if len(bi_list) > 0:
|
|
last_bi = bi_list[-1]
|
|
if len(bi_list) == 1:
|
|
if last_bi.dir == BI_DIR.UP:
|
|
updown.append(1)
|
|
last_updown = 1
|
|
else:
|
|
updown.append(-1)
|
|
last_updown = -1
|
|
else:
|
|
if last_updown == 1:
|
|
if last_bi.dir == BI_DIR.UP:
|
|
updown.append(0)
|
|
else:
|
|
updown.append(-1)
|
|
last_updown = -1
|
|
else:
|
|
if last_bi.dir == BI_DIR.DOWN:
|
|
updown.append(0)
|
|
else:
|
|
updown.append(1)
|
|
last_updown = 1
|
|
else:
|
|
updown.append(0)
|
|
bi_list = kl_datas.bi_list
|
|
if len(bi_list) > 0:
|
|
last_bi = bi_list[-1]
|
|
#if bi_list_pre_len > len(bi_list):
|
|
#print("Bi ", klu.time, pre_bi.idx, pre_bi.is_sure, bi_list[-1].idx, bi_list[-1].is_sure)
|
|
if last_bi.is_sure:
|
|
bi_sure.append(1)
|
|
#print(klu.time, last_bi.is_sure)
|
|
else:
|
|
bi_sure.append(0)
|
|
pre_bi = bi_list[-1]
|
|
bi_list_pre_len = len(bi_list)
|
|
else:
|
|
bi_sure.append(0)
|
|
#if bsps[-1] != 0 or updown[-1] != 0:
|
|
#print(klu.time, bsps[-1], updown[-1], bi_list[-1].is_sure)
|
|
self.chanIn = False
|
|
else:
|
|
klu = self.get_last_klu(dataframe)
|
|
if self.last_kline.time < klu.time:
|
|
self.chan.trigger_load({self.k_type: [klu]}) # 喂给CChan新增k线
|
|
self.last_kline = klu
|
|
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
|
|
#print(bsps)
|
|
#print(updown)
|
|
kl_datas = self.chan.kl_datas[self.k_type]
|
|
#for zs in kl_datas.zs_list:
|
|
#print(zs.begin.time, zs.end.time)
|
|
return bsps, updown, bi_sure
|
|
|
|
def get_bsp_state1(self, dataframe:DataFrame):
|
|
fields = "time,open,high,low,close,volume"
|
|
bsps = []
|
|
if self.chanIn:
|
|
kl_data = self.get_kl_data(dataframe)
|
|
self.chan.trigger_load({self.k_type: kl_data})
|
|
bsp_list = self.chan.get_bsp()
|
|
bsp_index = 0
|
|
for klu in kl_data:
|
|
if bsp_index >= len(bsp_list):
|
|
bsp_index = len(bsp_list) - 1
|
|
bsp = bsp_list[bsp_index]
|
|
if klu.idx == bsp.klu.idx:
|
|
bsp_type = self.get_bsp_type(bsp.type[0], bsp.is_buy)
|
|
if abs(bsp_type) == 1 or abs(bsp_type) == 10:
|
|
bsps.append(1)
|
|
else:
|
|
bsps.append(0)
|
|
bsp_index = bsp_index + 1
|
|
else:
|
|
bsps.append(0)
|
|
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
|
|
return bsps
|
|
def get_bsp_state(self, dataframe:DataFrame):
|
|
fields = "time,open,high,low,close,volume"
|
|
if self.chanIn:
|
|
kl_data = self.get_kl_data(dataframe)
|
|
bsp_list = []
|
|
bsp_list_pre_len = 0
|
|
last_bsp_value = 0
|
|
last_bsp_index = 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:
|
|
self.bsps.append(1)
|
|
#print(klu.time, klu.idx, last_bsp.klu.time, last_bsp.klu.idx, last_bsp_value, 98)
|
|
else:
|
|
self.bsps.append(99)
|
|
else:
|
|
if bsp_list_pre_len == len(bsp_list):
|
|
if klu.idx == last_bsp.klu.idx:
|
|
if last_bsp.klu.idx - last_bsp_index > 3:
|
|
last_bsp_value = self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy)
|
|
self.bsps.append(last_bsp_value)
|
|
else:
|
|
self.bsps.append(0)
|
|
last_bsp_index = last_bsp.klu.idx
|
|
#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:
|
|
self.bsps.append(0)
|
|
else:
|
|
if klu.idx == last_bsp.klu.idx:
|
|
if last_bsp.klu.idx - last_bsp_index > 3:
|
|
last_bsp_value = self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy)
|
|
self.bsps.append(last_bsp_value)
|
|
else:
|
|
self.bsps.append(0)
|
|
last_bsp_index = last_bsp.klu.idx
|
|
#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:
|
|
self.bsps.append(0)
|
|
else:
|
|
self.bsps.append(0)
|
|
bsp_list_pre_len = len(bsp_list)
|
|
self.chanIn = False
|
|
else:
|
|
klu = self.get_last_klu(dataframe)
|
|
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:
|
|
self.bsps.append(self.get_bsp_type(last_bsp.type[0], last_bsp.is_buy))
|
|
else:
|
|
self.bsps.append(0)
|
|
for index in range(0, len(self.bsps)):
|
|
if not (abs(self.bsps[index]) == 1 or abs(self.bsps[index]) == 2):
|
|
self.bsps[index] = 0
|
|
else:
|
|
if self.bsps[index] == 2:
|
|
self.bsps[index] = 10
|
|
else:
|
|
if self.bsps[index] == -2:
|
|
self.bsps[index] = -10
|
|
else:
|
|
if self.bsps[index] == 1:
|
|
self.bsps[index] = 1
|
|
else:
|
|
if self.bsps[index] == -1:
|
|
self.bsps[index] = -1
|
|
else:
|
|
self.bsps[index] = 0
|
|
return self.bsps
|
|
|