Files
Chan/chanlun/pipeline/orchestrator.py
T
jackyu66gitandCursor 74dec4e50b refactor: 缠论引擎包化与 Web 分层(ECR-001)
将根目录引擎迁入 chanlun/ 并保留兼容 shim;拆分 TF_DF 与 web 服务;
前端模块化;strategies 改用 chanlun 导入;补充 ESS 文档与 golden 回归。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 18:48:20 +08:00

188 lines
7.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import warnings
# 抑制 Docker 内 technical.util 的 fillna/ffill/bfill 的 pandas FutureWarningpandas 2.x 弃用 object 静默 downcast
warnings.filterwarnings(
"ignore",
category=FutureWarning,
message=".*Downcasting object dtype arrays on \\.fillna.*",
)
from datetime import timedelta
from pandas import DataFrame
from chanlun.core.ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_SEG_DIR, Chan_ZS_DIR, Chan_BSP_DIR, Chan_BSP_TYPE, Chan_KLC_FX, Chan_MACD_STATE, Chan_PRICE_TREND, Chan_KLU_PATTERN
from chanlun.core.ChanKLU import ChanKLU
from chanlun.core.ChanKLC import ChanKLC
from chanlun.core.ChanBI import ChanBI
from chanlun.core.ChanSBI import ChanSBI
from chanlun.core.ChanSEG import ChanSEG
from chanlun.core.ChanZS import ChanZS
from chanlun.core.ChanBSP import ChanBSP
import talib.abstract as ta
import pandas as pd
from technical.util import resample_to_interval
from decimal import Decimal
import numpy as np
from chanlun.indicators.ChanMACD import ChanMACD
from chanlun.pipeline.timeframe import TF_DF
from chanlun.analysis.ChanZone import StructureZone, StructureZoneConfig, analyze_structure_zones
class ChanLun():
def __init__(self):
self.time2m = 2
self.time3m = 3
self.time5m = 5
self.time10m = 10
self.time20m = 20
self.time_m_intervals = [2, 3, 5, 10, 20]
self.time_m_symbols = ['2m', '3m', '5m', '10m', '20m']
self.time30m = 30
self.time45m = 45
self.time_m15_intervals = [30, 45]
self.time_m15_symbols = ['30m', '45m']
self.time2h = 2*60
self.time4h = 4*60
self.time6h = 6*60
self.time8h = 8*60
self.time12h = 12*60
self.time16h = 16*60
self.time_h_intervals = [2*60, 4*60, 6*60, 8*60, 12*60, 16*60]
self.time_h_symbols = ['2h', '4h', '6h', '8h', '12h', '16h']
self.time2d = 2*24*60
self.time3d = 3*24*60
self.time_d_intervals = [2*24*60, 3*24*60]
self.time_d_symbols = ['2d', '3d']
self.time1w = 7*24*60
self.time2w = 14*24*60
self.time_w_intervals = [14*24*60]
self.time_w_symbols = ['2w']
self.time2M = 2*30*24*60
self.time3M = 3*30*24*60
self.time6M = 6*30*24*60
self.time1y = 12*30*24*60
self.time_M_intervals = [2*30*24*60, 3*30*24*60, 6*30*24*60, 12*30*24*60]
self.time_M_symbols = ['2M', '3M', '6M', '1y']
self.time_symbols = ['1m', '2m', '3m', '5m', '10m', '15m', '20m', '30m', '45m','1h', '2h', '4h', '6h', '8h', '12h', '16h', '1d', '2d', '3d']
self.tf_df_dict = {}
self.ema_symbols = ['5m', '15m', '30m', '45m', '1h', '2h', '4h', '8h', '12h', '1d', '2d', '3d']
self.tf_df = TF_DF()
def init_data(self, dataframe, intervals, timeframes):
for index in range(0, len(intervals)):
timeframe = timeframes[index]
interval = intervals[index]
self.tf_df_dict[timeframe] = TF_DF(dataframe, interval, timeframe)
def init_dataframes(self, dataframe_m=None, dataframe_15m=None, dataframe_h=None, dataframe_d=None, dataframe_w=None, dataframe_M=None):
self.tf_df_dict = {}
if dataframe_m is not None:
self.tf_df_dict['1m'] = TF_DF(dataframe_m, 1, '1m')
self.init_data(dataframe_m, self.time_m_intervals, self.time_m_symbols)
if dataframe_15m is not None:
self.tf_df_dict['15m'] = TF_DF(dataframe_15m, 1, '15m')
self.init_data(dataframe_15m, self.time_m15_intervals, self.time_m15_symbols)
if dataframe_h is not None:
self.tf_df_dict['1h'] = TF_DF(dataframe_h, 1, '1h')
self.init_data(dataframe_h, self.time_h_intervals, self.time_h_symbols)
if dataframe_d is not None:
self.tf_df_dict['1d'] = TF_DF(dataframe_d, 1, '1d')
self.init_data(dataframe_d, self.time_d_intervals, self.time_d_symbols)
if dataframe_w is not None and False:
self.tf_df_dict['1w'] = TF_DF(dataframe_w, 1, '1w')
self.init_data(dataframe_w, self.time_w_intervals, self.time_w_symbols)
if dataframe_M is not None and False:
self.tf_df_dict['1M'] = TF_DF(dataframe_M, 1, '1M')
self.init_data(dataframe_M, self.time_M_intervals, self.time_M_symbols)
def get_ema52_dict(self):
if len(self.tf_df_dict) > 0:
return {key: self.tf_df_dict[key].get_ema52() for key in self.ema_symbols}
return None
def get_ema24_dict(self):
if len(self.tf_df_dict) > 0:
return {key: self.tf_df_dict[key].get_ema24() for key in self.ema_symbols}
return None
def get_current_klc_dict(self):
if len(self.tf_df_dict) > 0:
return {key: self.tf_df_dict[key].get_current_klc() for key in self.ema_symbols}
return None
def get_tf_df_by_timeframe(self, timeframe):
if timeframe in self.tf_df_dict:
return self.tf_df_dict[timeframe]
return None
def check_price_ema52(self, price):
key_list = []
if len(self.tf_df_dict) > 0:
ema52_dict = self.get_ema52_dict()
for key in self.ema_symbols:
if ema52_dict[key] is not None:
if abs(price - ema52_dict[key]) < 100:
key_list.append(key)
return key_list
def get_ema_bsp(self, long_tf='1h', short_tf='15m'):
if long_tf in self.tf_df_dict and short_tf in self.tf_df_dict:
long_df = self.tf_df_dict[long_tf]
short_df = self.tf_df_dict[short_tf]
return long_df.get_ema_bsp(short_df)
return None
def get_bsp_state(self, dataframe):
return self.tf_df.get_bsp_state(dataframe)
def get_structure_zones(self, current_price=None, config=None):
if config is None:
config = StructureZoneConfig()
return analyze_structure_zones(
self.tf_df_dict,
self.ema_symbols,
current_price=current_price,
config=config,
)
# TF_DF methods ------------------------------------------
def get_ema_state(self, dataframe):
return self.tf_df.get_ema_state(dataframe)
def get_klu_state(self, dataframe):
return self.tf_df.get_klu_state(dataframe)
def check_fx(self, klc):
return self.tf_df.check_fx(klc)
def add_indicators1(self, df):
return self.tf_df.add_indicators(df)
def get_bi_list(self, dataframe):
return self.tf_df.get_bi_list(dataframe)
def get_kl_data(self, dataframe:DataFrame):
return self.tf_df.cal_kl_data(dataframe)
def cal_volume_ratio(self, dataframe, window=10):
return self.tf_df.cal_volume_ratio(dataframe, window)
def calculate_seg_zs(self, bi_list, seg_list):
return self.get_seg_zs_list(bi_list, seg_list)
def get_seg_list(self, bi_list):
return self.tf_df.get_seg_list(bi_list)
def cal_trend(self, klc_list):
return self.tf_df.cal_trend(klc_list)
def check_top_fx(self, last_bottom, klc):
return self.tf_df.check_top_fx(last_bottom, klc)
def check_bottom_fx(self, last_top, klc):
return self.tf_df.check_bottom_fx(last_top, klc)
def cal_bi_list(self, klc_list):
return self.tf_df.cal_bi_list(klc_list)
def find_first_bsp(self, bi_list, bi_zs_list):
return self.tf_df.find_first_bsp(bi_list, bi_zs_list)
def find_second_bsp(self, bi_list, first_bsp_list):
return self.tf_df.find_second_bsp(bi_list, first_bsp_list)
def find_all_bsp(self, bi_list, bi_zs_list):
return self.tf_df.find_all_bsp(bi_list, bi_zs_list)
def get_zs_list(self, bi_list, seg_list):
return self.tf_df.get_zs_list(bi_list, seg_list)
def cal_bi_zs(self, seg_list):
return self.tf_df.cal_bi_zs(seg_list)
def cal_bi_zs_list(self, bi_list):
#return self.tf_df.cal_bi_zs(bi_list)
return self.tf_df.cal_bi_zs_list(bi_list)
def get_bi_zs_list(self, bi_list):
return self.tf_df.get_bi_zs_list(bi_list)
def get_decimal(self, value):
return Decimal("{:.2f}".format(value))
def get_klc_list(self, klu_list):
return self.tf_df.get_klc_list(klu_list)
def get_klu_list(self, dataframe):
return self.tf_df.cal_klu_pattern(self.get_kl_data(dataframe))