refactor: 缠论引擎包化与 Web 分层(ECR-001)
将根目录引擎迁入 chanlun/ 并保留兼容 shim;拆分 TF_DF 与 web 服务; 前端模块化;strategies 改用 chanlun 导入;补充 ESS 文档与 golden 回归。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
"""TF_DF builder mixin — 由 split_tfdf_builders 自动生成,逻辑与原 TF_DF 一致。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import talib.abstract as ta
|
||||
from pandas import DataFrame
|
||||
from technical.util import resample_to_interval
|
||||
|
||||
from chanlun.core.ChanBI import ChanBI
|
||||
from chanlun.core.ChanBIZS import ChanBIZS
|
||||
from chanlun.core.ChanBSP import ChanBSP
|
||||
from chanlun.core.ChanEnum import (
|
||||
Chan_BI_DIR,
|
||||
Chan_BSP_DIR,
|
||||
Chan_BSP_TYPE,
|
||||
Chan_FX_TYPE,
|
||||
Chan_K_DIR,
|
||||
Chan_KLC_FX,
|
||||
Chan_KLC_STATE,
|
||||
Chan_KLINE_DIR,
|
||||
Chan_KLU_PATTERN,
|
||||
Chan_PRICE_TREND,
|
||||
Chan_SEG_DIR,
|
||||
Chan_ZS_DIR,
|
||||
)
|
||||
from chanlun.core.ChanKLC import ChanKLC
|
||||
from chanlun.core.ChanKLU import ChanKLU
|
||||
from chanlun.core.ChanSBI import ChanSBI
|
||||
from chanlun.core.ChanSEG import ChanSEG
|
||||
from chanlun.core.ChanZS import ChanZS, ChanZS_Big
|
||||
from chanlun.indicators.ChanMACD import ChanMACD
|
||||
|
||||
|
||||
class SegBuilderMixin:
|
||||
def get_seg_list(self, bi_list):
|
||||
seg_list = []
|
||||
up_bi_list = []
|
||||
down_bi_list = []
|
||||
last_up_bi = None
|
||||
last_down_bi = None
|
||||
last_up_sbi = None
|
||||
last_down_sbi = None
|
||||
last_seg = None
|
||||
up_sbi_list = []
|
||||
down_sbi_list = []
|
||||
look_for_bottom = False
|
||||
look_for_top = False
|
||||
for bi in bi_list:
|
||||
#print(len(up_sbi_list), len(down_sbi_list))
|
||||
if len(seg_list) > 0:
|
||||
# Last seg is up
|
||||
if last_seg.dir == Chan_SEG_DIR.UP:
|
||||
if bi.dir == Chan_BI_DIR.DOWN:
|
||||
if len(down_sbi_list) > 1:
|
||||
# Check down sbi inclusion
|
||||
included = last_down_sbi.check_bi_included(bi)
|
||||
if not included:
|
||||
down_sbi = ChanSBI(bi, len(down_sbi_list), bi.dir)
|
||||
last_down_sbi.set_next(down_sbi)
|
||||
last_down_sbi.set_end_bi(last_down_bi)
|
||||
down_sbi.set_pre(last_down_sbi)
|
||||
down_sbi_list.append(down_sbi)
|
||||
fx = last_down_sbi.check_fx()
|
||||
# Found top
|
||||
if fx == Chan_FX_TYPE.TOP:
|
||||
if look_for_top:
|
||||
seg_list[-2].set_sure(bi)
|
||||
look_for_top = False
|
||||
#print(bi.start_time, look_for_top, "UP 1")
|
||||
# Has gap and search for bottom fx
|
||||
if last_down_sbi.has_fx_gap:
|
||||
look_for_bottom = True
|
||||
last_seg.pre_set_end_bi(bi_list[last_down_sbi.start_bi.index - 1])
|
||||
seg = ChanSEG(last_down_sbi.start_bi, len(seg_list), Chan_SEG_DIR.DOWN, bi)
|
||||
seg_list.append(seg)
|
||||
last_seg.set_next(seg)
|
||||
seg.set_pre(last_seg)
|
||||
last_seg = seg
|
||||
up_sbi_list = []
|
||||
last_up_sbi = ChanSBI(last_up_bi, len(up_sbi_list), last_up_bi.dir)
|
||||
up_sbi_list.append(last_up_sbi)
|
||||
#up_sbi_list.append(last_up_sbi)
|
||||
#print(last_up_bi.start_time, last_up_sbi.start_bi.start_time, "Reset up sbi list 1")
|
||||
#print(bi.start_time, look_for_top, "UP 2")
|
||||
# No gap end SEG
|
||||
else:
|
||||
if look_for_bottom:
|
||||
look_for_bottom = False
|
||||
last_seg.set_start_bi(last_down_sbi.start_bi)
|
||||
seg_list[-2].set_end_bi(bi_list[last_down_sbi.start_bi.index - 1], bi)
|
||||
up_sbi_list = []
|
||||
last_up_sbi = ChanSBI(last_up_bi, len(up_sbi_list), last_up_bi.dir)
|
||||
up_sbi_list.append(last_up_sbi)
|
||||
last_seg.add_bi(bi)
|
||||
#up_sbi_list.append(last_up_sbi)
|
||||
#print(last_up_bi.start_time, last_up_sbi.start_bi.start_time, "Reset up sbi list 2")
|
||||
#print(bi.start_time, look_for_top, "UP 3")
|
||||
else:
|
||||
last_seg.set_end_bi(bi_list[last_down_sbi.start_bi.index - 1], bi)
|
||||
seg = ChanSEG(last_down_sbi.start_bi, len(seg_list), Chan_SEG_DIR.DOWN, bi)
|
||||
seg_list.append(seg)
|
||||
last_seg.set_next(seg)
|
||||
seg.set_pre(last_seg)
|
||||
last_seg = seg
|
||||
#print(last_down_sbi.end_bi.start_time, "Normal UP SEG", last_up_sbi.start_bi.start_time, bi.start_time)
|
||||
#l_up_sbi = up_sbi_list[-1]
|
||||
up_sbi_list = []
|
||||
last_up_sbi = ChanSBI(last_up_bi, len(up_sbi_list), last_up_bi.dir)
|
||||
up_sbi_list.append(last_up_sbi)
|
||||
#up_sbi_list.append(last_up_sbi)
|
||||
#print(last_up_bi.start_time, last_up_sbi.start_bi.start_time, "Reset up sbi list 3")
|
||||
last_down_sbi = down_sbi
|
||||
last_seg.add_bi(bi)
|
||||
else:
|
||||
if len(down_sbi_list) == 1:
|
||||
included = last_down_sbi.check_bi_included(bi)
|
||||
if not included:
|
||||
down_sbi = ChanSBI(bi, len(down_sbi_list), bi.dir)
|
||||
last_down_sbi.set_next(down_sbi)
|
||||
last_down_sbi.set_end_bi(last_down_bi)
|
||||
down_sbi.set_pre(last_down_sbi)
|
||||
down_sbi_list.append(down_sbi)
|
||||
last_down_sbi = down_sbi
|
||||
#print(bi.start_time, look_for_top, "UP 4")
|
||||
last_seg.add_bi(bi)
|
||||
|
||||
else:
|
||||
last_down_sbi = ChanSBI(bi, len(down_sbi_list), bi.dir)
|
||||
down_sbi_list.append(last_down_sbi)
|
||||
last_seg.add_bi(bi)
|
||||
#print(bi.start_time, look_for_top, "UP 5")
|
||||
else:
|
||||
if last_up_sbi:
|
||||
included = last_up_sbi.check_bi_included(bi)
|
||||
if not included:
|
||||
up_sbi = ChanSBI(bi, len(up_sbi_list), bi.dir)
|
||||
last_up_sbi.set_next(up_sbi)
|
||||
last_up_sbi.set_end_bi(last_up_bi)
|
||||
up_sbi.set_pre(last_up_sbi)
|
||||
up_sbi_list.append(up_sbi)
|
||||
last_up_sbi = up_sbi
|
||||
#print(bi.start_time, look_for_top, "UP 6")
|
||||
last_seg.add_bi(bi)
|
||||
|
||||
# Last seg is down
|
||||
else:
|
||||
if bi.dir == Chan_BI_DIR.UP:
|
||||
if len(up_sbi_list) > 1:
|
||||
# Check down sbi inclusion
|
||||
included = last_up_sbi.check_bi_included(bi)
|
||||
if not included:
|
||||
up_sbi = ChanSBI(bi, len(up_sbi_list), bi.dir)
|
||||
last_up_sbi.set_next(up_sbi)
|
||||
last_up_sbi.set_end_bi(last_up_bi)
|
||||
up_sbi.set_pre(last_up_sbi)
|
||||
up_sbi_list.append(up_sbi)
|
||||
fx = last_up_sbi.check_fx()
|
||||
# Found bottom
|
||||
if fx == Chan_FX_TYPE.BOTTOM:
|
||||
if look_for_bottom:
|
||||
seg_list[-2].set_sure(bi)
|
||||
look_for_bottom = False
|
||||
#print(bi.start_time, look_for_top, "DOWN 1")
|
||||
# Has gap and search for bottom fx
|
||||
if last_up_sbi.has_fx_gap:
|
||||
look_for_top = True
|
||||
last_seg.pre_set_end_bi(bi_list[last_up_sbi.start_bi.index - 1])
|
||||
seg = ChanSEG(last_up_sbi.start_bi, len(seg_list), Chan_SEG_DIR.UP, bi)
|
||||
seg_list.append(seg)
|
||||
last_seg.set_next(seg)
|
||||
seg.set_pre(last_seg)
|
||||
last_seg = seg
|
||||
down_sbi_list = []
|
||||
last_down_sbi = ChanSBI(last_down_bi, len(down_sbi_list), last_down_bi.dir)
|
||||
down_sbi_list.append(last_down_sbi)
|
||||
#down_sbi_list.append(last_down_sbi)
|
||||
#print(last_down_bi.start_time, last_down_sbi.start_bi.start_time, "Reset down sbi list 1")
|
||||
#print(bi.start_time, look_for_top, "DOWN 2")
|
||||
# No gap end SEG
|
||||
else:
|
||||
if look_for_top:
|
||||
look_for_top = False
|
||||
last_seg.set_start_bi(last_up_sbi.start_bi)
|
||||
seg_list[-2].set_end_bi(bi_list[last_up_sbi.start_bi.index - 1], bi)
|
||||
down_sbi_list = []
|
||||
last_down_sbi = ChanSBI(last_down_bi, len(down_sbi_list), last_down_bi.dir)
|
||||
down_sbi_list.append(last_down_sbi)
|
||||
last_seg.add_bi(bi)
|
||||
#down_sbi_list.append(last_down_sbi)
|
||||
#print(last_down_bi.start_time, last_down_sbi.start_bi.start_time, "Reset down sbi list 2")
|
||||
#print(bi.start_time, look_for_top, "DOWN 3")
|
||||
else:
|
||||
last_seg.set_end_bi(bi_list[last_up_sbi.start_bi.index - 1], bi)
|
||||
seg = ChanSEG(last_up_sbi.start_bi, len(seg_list), Chan_SEG_DIR.UP, bi)
|
||||
#print(last_up_sbi.start_bi.start_time)
|
||||
last_seg.set_next(seg)
|
||||
seg.set_pre(last_seg)
|
||||
seg_list.append(seg)
|
||||
last_seg = seg
|
||||
#print(last_up_sbi.end_bi.start_time, "Normal DOWN SEG", last_down_sbi.start_bi.start_time, bi.start_time)
|
||||
down_sbi_list = []
|
||||
last_down_sbi = ChanSBI(last_down_bi, len(down_sbi_list), last_down_bi.dir)
|
||||
down_sbi_list.append(last_down_sbi)
|
||||
#down_sbi_list.append(last_down_sbi)
|
||||
#print(last_down_bi.start_time, last_down_sbi.start_bi.start_time, "Reset down sbi list 3")
|
||||
last_up_sbi = up_sbi
|
||||
last_seg.add_bi(bi)
|
||||
else:
|
||||
if len(up_sbi_list) == 1:
|
||||
#last_up_sbi = up_sbi_list[-1]
|
||||
included = last_up_sbi.check_bi_included(bi)
|
||||
if not included:
|
||||
up_sbi = ChanSBI(bi, len(up_sbi_list), bi.dir)
|
||||
last_up_sbi.set_next(up_sbi)
|
||||
last_up_sbi.set_end_bi(last_up_bi)
|
||||
up_sbi.set_pre(last_up_sbi)
|
||||
up_sbi_list.append(up_sbi)
|
||||
last_up_sbi = up_sbi
|
||||
last_seg.add_bi(bi)
|
||||
#print(bi.start_time, look_for_top, "DOWN 4")
|
||||
else:
|
||||
last_up_sbi = ChanSBI(bi, len(up_sbi_list), bi.dir)
|
||||
up_sbi_list.append(last_up_sbi)
|
||||
last_seg.add_bi(bi)
|
||||
#print(bi.start_time, look_for_top, "DOWN 5")
|
||||
else:
|
||||
if last_down_sbi:
|
||||
included = last_down_sbi.check_bi_included(bi)
|
||||
if not included:
|
||||
down_sbi = ChanSBI(bi, len(down_sbi_list), bi.dir)
|
||||
last_down_sbi.set_next(down_sbi)
|
||||
last_down_sbi.set_end_bi(last_down_bi)
|
||||
down_sbi.set_pre(last_down_sbi)
|
||||
down_sbi_list.append(down_sbi)
|
||||
last_down_sbi = down_sbi
|
||||
last_seg.add_bi(bi)
|
||||
#print(bi.start_time, look_for_top, look_for_bottom, "DOWN 6")
|
||||
# len(seg_list) = 0
|
||||
else:
|
||||
if bi.check_overlap():
|
||||
if bi.dir == Chan_BI_DIR.UP:
|
||||
seg = ChanSEG(bi, len(seg_list), Chan_SEG_DIR.UP, bi)
|
||||
last_up_bi = bi
|
||||
last_up_sbi = ChanSBI(bi, len(up_sbi_list), bi.dir)
|
||||
seg_list.append(seg)
|
||||
last_seg = seg
|
||||
#print(bi.start_time, 'Create first UP SEG')
|
||||
else:
|
||||
seg = ChanSEG(bi, len(seg_list), Chan_SEG_DIR.DOWN, bi)
|
||||
last_down_bi = bi
|
||||
last_down_sbi = ChanSBI(bi, len(down_sbi_list), bi.dir)
|
||||
seg_list.append(seg)
|
||||
last_seg = seg
|
||||
#print(bi.start_time, 'Create first DOWN SEG')
|
||||
if bi.dir == Chan_BI_DIR.UP:
|
||||
last_up_bi = bi
|
||||
up_bi_list.append(bi)
|
||||
else:
|
||||
last_down_bi = bi
|
||||
down_bi_list.append(bi)
|
||||
"""
|
||||
if len(seg_list) > 1:
|
||||
seg = seg_list[-1]
|
||||
last_seg = seg_list[-2]
|
||||
last_seg_bi = last_seg.bi_list[-3]
|
||||
bi_index = seg.start_bi.index
|
||||
for i in range(bi_index, len(bi_list) - 1):
|
||||
# last seg is down
|
||||
if seg.dir == Chan_SEG_DIR.UP:
|
||||
if bi_list[i].dir == Chan_BI_DIR.UP:
|
||||
last_seg_peak = last_seg_bi.high
|
||||
if bi_list[i].high > last_seg_peak:
|
||||
# The confirmed
|
||||
print("Last UP seg is broken, create a new seg. 1")
|
||||
seg.pre_set_end_bi(bi_list[i])
|
||||
seg = ChanSEG(bi_list[i+1], len(seg_list), Chan_SEG_DIR.DOWN, bi)
|
||||
seg_list.append(seg)
|
||||
last_seg = seg_list[-2]
|
||||
if len(last_seg.bi_list) > 3:
|
||||
last_seg_bi = last_seg.bi_list[-3]
|
||||
|
||||
else:
|
||||
if bi_list[i].dir == Chan_BI_DIR.DOWN:
|
||||
last_seg_peak = last_seg_bi.low
|
||||
if bi_list[i].low < last_seg_peak:
|
||||
print("Last DOWN seg is broken, create a new seg. 1")
|
||||
seg.pre_set_end_bi(bi_list[i])
|
||||
seg = ChanSEG(bi_list[i+1], len(seg_list), Chan_SEG_DIR.UP, bi)
|
||||
seg_list.append(seg)
|
||||
last_seg = seg_list[-2]
|
||||
if len(last_seg.bi_list) > 3:
|
||||
last_seg_bi = last_seg.bi_list[-3]
|
||||
else:
|
||||
if len(seg_list) == 1:
|
||||
last_seg = seg_list[-1]
|
||||
bi_index = last_seg.bi_list[0].index
|
||||
for i in range(bi_index, len(bi_list) - 1):
|
||||
if i > bi_index + 2:
|
||||
last_seg_peak = bi_list[i-2].high
|
||||
# last seg is down
|
||||
if last_seg.dir == Chan_SEG_DIR.DOWN:
|
||||
if bi_list[i].dir == Chan_BI_DIR.UP:
|
||||
if bi_list[i].high > last_seg_peak:
|
||||
print("Last seg is broken, create a new seg. 2")
|
||||
last_seg.pre_set_end_bi(bi_list[i-1])
|
||||
seg = ChanSEG(bi_list[i], len(seg_list), Chan_SEG_DIR.UP, bi)
|
||||
seg_list.append(seg)
|
||||
last_seg = seg
|
||||
last_seg_bi = bi_list[i]
|
||||
break
|
||||
"""
|
||||
#self.cal_bi_zs(seg_list)
|
||||
return seg_list
|
||||
Reference in New Issue
Block a user