[update] 基础组件更新

This commit is contained in:
msincenselee 2021-08-30 09:04:30 +08:00
parent 344f877bda
commit 98ab549e0d
16 changed files with 889 additions and 440 deletions

View File

@ -3,6 +3,7 @@
下载通达信股票合约1分钟&日线bar => vnpy项目目录/bar_data/ 下载通达信股票合约1分钟&日线bar => vnpy项目目录/bar_data/
上海股票 => SSE子目录 上海股票 => SSE子目录
深圳股票 => SZSE子目录 深圳股票 => SZSE子目录
修改为多进程模式
""" """
import os import os
import sys import sys
@ -10,6 +11,10 @@ import csv
import json import json
from collections import OrderedDict from collections import OrderedDict
import pandas as pd import pandas as pd
from multiprocessing import Pool
from concurrent.futures import ThreadPoolExecutor
from copy import copy
vnpy_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) vnpy_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
if vnpy_root not in sys.path: if vnpy_root not in sys.path:
@ -35,97 +40,163 @@ api_01 = TdxStockData()
# 额外需要数据下载的基金列表 # 额外需要数据下载的基金列表
stock_list = load_json('stock_list.json') stock_list = load_json('stock_list.json')
# 强制更新缓存
api_01.cache_config()
symbol_dict = api_01.symbol_dict symbol_dict = api_01.symbol_dict
#
# thread_executor = ThreadPoolExecutor(max_workers=1)
# thread_tasks = []
# 下载所有的股票数据
num_stocks = 0
for period in ['1min', '1day']:
for symbol in symbol_dict.keys():
symbol_info = symbol_dict[symbol]
stock_code = symbol_info['code']
if ('stock_type' in symbol_info.keys() and symbol_info['stock_type'] in ['stock_cn', 'cb_cn']) or stock_code in stock_list:
# if stock_code in stock_list:
# print(symbol_info['code'])
if symbol_info['exchange'] == 'SZSE':
exchange_name = '深交所'
exchange = Exchange.SZSE
else:
exchange_name = '上交所'
exchange = Exchange.SSE
else:
continue
num_stocks += 1
stock_name = symbol_info.get('name') def refill(symbol_info):
print(f'开始更新:{exchange_name}/{stock_name}, 代码:{stock_code}') period = symbol_info['period']
bar_file_folder = os.path.abspath(os.path.join(bar_data_folder, f'{exchange.value}')) progress = symbol_info['progress']
if not os.path.exists(bar_file_folder): # print("{}_{}".format(period, symbol_info['code']))
os.makedirs(bar_file_folder) # return
# csv数据文件名 stock_code = symbol_info['code']
bar_file_path = os.path.abspath(os.path.join(bar_file_folder, f'{stock_code}_{period[0:2]}.csv'))
# 如果文件存在, # if stock_code in stock_list:
if os.path.exists(bar_file_path): # print(symbol_info['code'])
# 取最后一条时间 if symbol_info['exchange'] == 'SZSE':
last_dt = get_csv_last_dt(bar_file_path) exchange_name = '深交所'
else: exchange = Exchange.SZSE
last_dt = None else:
exchange_name = '上交所'
exchange = Exchange.SSE
if last_dt: # num_stocks += 1
start_dt = last_dt - timedelta(days=1)
print(f'文件{bar_file_path}存在,最后时间:{start_date}')
else:
start_dt = datetime.strptime(start_date, '%Y%m%d')
print(f'文件{bar_file_path}不存在,或读取最后记录错误,开始时间:{start_date}')
result, bars = api_01.get_bars(symbol=stock_code, stock_name = symbol_info.get('name')
period=period, print(f'开始更新:{exchange_name}/{stock_name}, 代码:{stock_code}')
callback=None, bar_file_folder = os.path.abspath(os.path.join(bar_data_folder, f'{exchange.value}'))
start_dt=start_dt, if not os.path.exists(bar_file_folder):
return_bar=False) os.makedirs(bar_file_folder)
# [dict] => dataframe # csv数据文件名
if not result or len(bars) == 0: p_name = period.replace('min', 'm').replace('day', 'd').replace('hour', 'h')
continue bar_file_path = os.path.abspath(os.path.join(bar_file_folder, f'{stock_code}_{p_name}.csv'))
# 全新数据 # 如果文件存在,
if last_dt is None: if os.path.exists(bar_file_path):
data_df = pd.DataFrame(bars) # 取最后一条时间
data_df.set_index('datetime', inplace=True) last_dt = get_csv_last_dt(bar_file_path)
data_df = data_df.sort_index() else:
# print(data_df.head()) last_dt = None
print(data_df.tail())
data_df.to_csv(bar_file_path, index=True)
print(f'首次更新{stock_code} {stock_name}数据 => 文件{bar_file_path}')
# 增量更新 if last_dt:
else: start_dt = last_dt - timedelta(days=1)
# 获取标题 print(f'文件{bar_file_path}存在,最后时间:{start_dt}')
headers = [] else:
with open(bar_file_path, "r", encoding='utf8') as f: start_dt = datetime.strptime(start_date, '%Y%m%d')
reader = csv.reader(f) print(f'文件{bar_file_path}不存在,或读取最后记录错误,开始时间:{start_date}')
for header in reader:
headers = header
break
bar_count = 0 d1 = datetime.now()
# 写入所有大于最后bar时间的数据 result, bars = api_01.get_bars(symbol=stock_code,
# with open(bar_file_path, 'a', encoding='utf8', newline='\n') as csvWriteFile: period=period,
with open(bar_file_path, 'a', encoding='utf8') as csvWriteFile: callback=None,
start_dt=start_dt,
return_bar=False)
# [dict] => dataframe
if not result or len(bars) == 0:
return
writer = csv.DictWriter(f=csvWriteFile, fieldnames=headers, dialect='excel', need_resample = False
extrasaction='ignore') # 全新数据
for bar in bars: if last_dt is None:
if bar['datetime'] <= last_dt: data_df = pd.DataFrame(bars)
continue data_df.set_index('datetime', inplace=True)
bar_count += 1 data_df = data_df.sort_index()
writer.writerow(bar) # print(data_df.head())
print(data_df.tail())
data_df.to_csv(bar_file_path, index=True)
d2 = datetime.now()
microseconds = (d1 - d1).microseconds
print(f'{progress}% 首次更新{stock_code} {stock_name}数据 {microseconds} 毫秒=> 文件{bar_file_path}')
need_resample = True
print(f'更新{stock_code} {stock_name} 数据 => 文件{bar_file_path}, 最后记录:{bars[-1]}') # 增量更新
else:
# 获取标题
headers = []
with open(bar_file_path, "r", encoding='utf8') as f:
reader = csv.reader(f)
for header in reader:
headers = header
break
# 输出 5、15、30分钟的数据 bar_count = 0
if period == '1min': # 写入所有大于最后bar时间的数据
out_files, err_msg = resample_bars_file(vnpy_root=vnpy_root, symbol=stock_code, exchange=exchange, x_mins=[5,15,30]) # with open(bar_file_path, 'a', encoding='utf8', newline='\n') as csvWriteFile:
with open(bar_file_path, 'a', encoding='utf8') as csvWriteFile:
msg = 'tdx股票数据补充完毕: num_stocks={}'.format(num_stocks) writer = csv.DictWriter(f=csvWriteFile, fieldnames=headers, dialect='excel',
send_wx_msg(content=msg) extrasaction='ignore')
os._exit(0) for bar in bars:
if bar['datetime'] <= last_dt:
continue
bar_count += 1
writer.writerow(bar)
if not need_resample:
need_resample = True
d2 = datetime.now()
microseconds = round((d2 - d1).microseconds / 100, 0)
print(f'{progress}%,更新{stock_code} {stock_name} 数据 {microseconds}毫秒 => 文件{bar_file_path}, 最后记录:{bars[-1]}')
# 采用多线程方式输出 5、15、30分钟的数据
# if period == '1min' and need_resample:
# task = thread_executor.submit(resample, stock_code, exchange, [5, 15, 30])
# thread_tasks.append(task)
def resample(symbol, exchange, x_mins=[5, 15, 30]):
"""
更新多周期文件
:param symbol:
:param exchange:
:param x_mins:
:return:
"""
d1 = datetime.now()
out_files, err_msg = resample_bars_file(vnpy_root=vnpy_root,
symbol=symbol,
exchange=exchange,
x_mins=x_mins)
d2 = datetime.now()
microseconds = round((d2 - d1).microseconds / 100, 0)
if len(err_msg) > 0:
print(err_msg, file=sys.stderr)
if out_files:
print(f'{microseconds}毫秒,生成 =>{out_files}')
if __name__ == '__main__':
# 下载所有的股票数据
num_progress = 0
total_tasks = len(symbol_dict.keys()) * 2
tasks = []
for period in ['1min', '5min', '15min', '30min', '1hour', '1day']:
for symbol in symbol_dict.keys():
info = copy(symbol_dict[symbol])
stock_code = info['code']
if ('stock_type' in info.keys() and info['stock_type'] in ['stock_cn',
'cb_cn']) or stock_code in stock_list:
info['period'] = period
tasks.append(info)
# if len(tasks) > 12:
# break
total_tasks = len(tasks)
for task in tasks:
num_progress += 1
task['progress'] = round(100 * num_progress / total_tasks, 2)
p = Pool(12)
p.map(refill, tasks)
p.close()
p.join()
#
msg = 'tdx股票数据补充完毕: num_stocks={}'.format(total_tasks)
send_wx_msg(content=msg)
os._exit(0)

View File

@ -1921,7 +1921,7 @@ class BackTestingEngine(object):
# 返回回测结果 # 返回回测结果
d = {} d = {}
d['init_capital'] = self.init_capital d['init_capital'] = self.init_capital
d['profit'] = self.cur_capital - self.init_capital d['profit'] = self.net_capital - self.init_capital
d['net_capital'] = self.net_capital d['net_capital'] = self.net_capital
d['max_capital'] = self.max_net_capital # 取消原 maxCapital d['max_capital'] = self.max_net_capital # 取消原 maxCapital
@ -2006,8 +2006,8 @@ class BackTestingEngine(object):
result_info.update({u'期末资金': d['net_capital']}) result_info.update({u'期末资金': d['net_capital']})
self.output(u'期末资金:\t%s' % format_number(d['net_capital'])) self.output(u'期末资金:\t%s' % format_number(d['net_capital']))
result_info.update({u'平仓盈亏': d['profit']}) result_info.update({u'盈亏': d['profit']})
self.output(u'平仓盈亏:\t%s' % format_number(d['profit'])) self.output(u'盈亏:\t%s' % format_number(d['profit']))
result_info.update({u'资金最高净值': d['max_capital']}) result_info.update({u'资金最高净值': d['max_capital']})
self.output(u'资金最高净值:\t%s' % format_number(d['max_capital'])) self.output(u'资金最高净值:\t%s' % format_number(d['max_capital']))

View File

@ -1316,7 +1316,7 @@ class CtaFutureTemplate(CtaTemplate):
up_grids_info = "" up_grids_info = ""
for grid in list(self.gt.up_grids): for grid in list(self.gt.up_grids):
if not grid.open_status and grid.order_status: if grid.open_status and grid.order_status:
up_grids_info += f'平空中: [已平:{grid.traded_volume} => 目标:{grid.volume}, 委托时间:{grid.order_time}]\n' up_grids_info += f'平空中: [已平:{grid.traded_volume} => 目标:{grid.volume}, 委托时间:{grid.order_time}]\n'
if len(grid.order_ids) > 0: if len(grid.order_ids) > 0:
up_grids_info += f'委托单号:{grid.order_ids}' up_grids_info += f'委托单号:{grid.order_ids}'
@ -1333,7 +1333,7 @@ class CtaFutureTemplate(CtaTemplate):
dn_grids_info = "" dn_grids_info = ""
for grid in list(self.gt.dn_grids): for grid in list(self.gt.dn_grids):
if not grid.open_status and grid.order_status: if grid.open_status and grid.order_status:
dn_grids_info += f'平多中: [已平:{grid.traded_volume} => 目标:{grid.volume}, 委托时间:{grid.order_time}]\n' dn_grids_info += f'平多中: [已平:{grid.traded_volume} => 目标:{grid.volume}, 委托时间:{grid.order_time}]\n'
if len(grid.order_ids) > 0: if len(grid.order_ids) > 0:
dn_grids_info += f'委托单号:{grid.order_ids}' dn_grids_info += f'委托单号:{grid.order_ids}'

View File

@ -452,7 +452,14 @@ class PortfolioTestingEngine(BackTestingEngine):
ticks = [] ticks = []
if not os.path.isfile(file_path): if not os.path.isfile(file_path):
self.write_log(u'{}文件不存在'.format(file_path)) self.write_log(u'{}文件不存在'.format(file_path))
return None file_path = os.path.abspath(
os.path.join(
tick_folder,
tick_date.strftime('%Y%m'),
'{}_{}.csv'.format(symbol.lower(), tick_date.strftime('%Y%m%d'))))
if not os.path.isfile(file_path):
self.write_log(u'{}文件不存在'.format(file_path))
return None
try: try:
df = pd.read_csv(file_path, parse_dates=False) df = pd.read_csv(file_path, parse_dates=False)
# datetime,symbol,exchange,last_price,highest,lowest,volume,amount,open_interest,upper_limit,lower_limit, # datetime,symbol,exchange,last_price,highest,lowest,volume,amount,open_interest,upper_limit,lower_limit,
@ -589,8 +596,32 @@ class PortfolioTestingEngine(BackTestingEngine):
time=dt.strftime('%H:%M:%S.%f'), time=dt.strftime('%H:%M:%S.%f'),
trading_day=test_day.strftime('%Y-%m-%d'), trading_day=test_day.strftime('%Y-%m-%d'),
last_price=last_price, last_price=last_price,
volume=tick_data['volume'] volume=tick_data['volume'],
ask_price_1=float(tick_data.get('ask_price_1',0)),
ask_volume_1=int(tick_data.get('ask_volume_1',0)),
bid_price_1=float(tick_data.get('bid_price_1',0)),
bid_volume_1=int(tick_data.get('bid_volume_1',0))
) )
if tick_data.get('ask_price_5',0) > 0:
tick.ask_price_2 = float(tick_data.get('ask_price_2',0))
tick.ask_volume_2 = int(tick_data.get('ask_volume_2', 0))
tick.bid_price_2 = float(tick_data.get('bid_price_2', 0))
tick.bid_volume_2 = int(tick_data.get('bid_volume_2', 0))
tick.ask_price_3 = float(tick_data.get('ask_price_3', 0))
tick.ask_volume_3 = int(tick_data.get('ask_volume_3', 0)),
tick.bid_price_3 = float(tick_data.get('bid_price_3', 0)),
tick.bid_volume_3 = int(tick_data.get('bid_volume_3', 0))
tick.ask_price_4 = float(tick_data.get('ask_price_4', 0))
tick.ask_volume_4 = int(tick_data.get('ask_volume_4', 0)),
tick.bid_price_4 = float(tick_data.get('bid_price_4', 0)),
tick.bid_volume_4 = int(tick_data.get('bid_volume_4', 0))
tick.ask_price_5 = float(tick_data.get('ask_price_5', 0))
tick.ask_volume_5 = int(tick_data.get('ask_volume_5', 0)),
tick.bid_price_5 = float(tick_data.get('bid_price_5', 0)),
tick.bid_volume_5 = int(tick_data.get('bid_volume_5', 0))
self.new_tick(tick) self.new_tick(tick)

View File

@ -5,6 +5,9 @@ import sys
from abc import ABC from abc import ABC
from enum import Enum from enum import Enum
from logging import INFO, ERROR from logging import INFO, ERROR
import json
import numpy as np
import datetime
from vnpy.trader.constant import Direction # noqa from vnpy.trader.constant import Direction # noqa
@ -71,3 +74,20 @@ class CtaComponent(ABC):
self.strategy.write_log(msg=content, level=level) self.strategy.write_log(msg=content, level=level)
else: else:
print(content, file=sys.stderr) print(content, file=sys.stderr)
class MyEncoder(json.JSONEncoder):
"""
自定义转换器处理np,datetime等不能被json转换得问题
"""
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
elif isinstance(obj, datetime):
return obj.strftime('%Y-%m-%d %H:%M:%S')
else:
return super(MyEncoder, self).default(obj)

View File

@ -10,7 +10,7 @@ import traceback
from collections import OrderedDict from collections import OrderedDict
from datetime import datetime from datetime import datetime
from vnpy.trader.utility import get_folder_path from vnpy.trader.utility import get_folder_path
from vnpy.component.base import Direction, CtaComponent from vnpy.component.base import Direction, CtaComponent,MyEncoder
""" """
网格交易用于套利单 网格交易用于套利单
@ -894,7 +894,7 @@ class CtaGridTrade(CtaComponent):
data = self.to_json() data = self.to_json()
with open(grid_json_file, 'w', encoding='utf8') as f: with open(grid_json_file, 'w', encoding='utf8') as f:
json_data = json.dumps(data, indent=4, ensure_ascii=False) json_data = json.dumps(data, indent=4, ensure_ascii=False, cls=MyEncoder)
f.write(json_data) f.write(json_data)
self.write_log(u'GrideTrade保存文件{}完成'.format(grid_json_file)) self.write_log(u'GrideTrade保存文件{}完成'.format(grid_json_file))

View File

@ -28,8 +28,9 @@ from vnpy.component.base import (
MARKET_ZJ) MARKET_ZJ)
from vnpy.component.cta_period import CtaPeriod, Period from vnpy.component.cta_period import CtaPeriod, Period
from vnpy.trader.object import BarData, TickData from vnpy.trader.object import BarData, TickData
from vnpy.trader.constant import Interval, Color from vnpy.trader.constant import Interval, Color, ChanSignals
from vnpy.trader.utility import round_to, get_trading_date, get_underlying_symbol from vnpy.trader.utility import round_to, get_trading_date, get_underlying_symbol
from vnpy.component.cta_utility import check_chan_xt,check_chan_xt_three_bi, check_qsbc_2nd
try: try:
from vnpy.component.chanlun import ChanGraph, ChanLibrary from vnpy.component.chanlun import ChanGraph, ChanLibrary
@ -206,6 +207,8 @@ class CtaLineBar(object):
self.export_bi_filename = None # 通过缠论笔csv文件 self.export_bi_filename = None # 通过缠论笔csv文件
self.export_zs_filename = None # 通过缠论的笔中枢csv文件 self.export_zs_filename = None # 通过缠论的笔中枢csv文件
self.export_duan_filename = None # 通过缠论的线段csv文件 self.export_duan_filename = None # 通过缠论的线段csv文件
self.export_xt_filename = None # 缠论笔的形态csv文件, 满足 strategy_name_xt_n_signals.csv
# n 会转换为 35791113
self.pre_bi_start = None # 前一个笔的时间 self.pre_bi_start = None # 前一个笔的时间
self.pre_zs_start = None # 前一个中枢的时间 self.pre_zs_start = None # 前一个中枢的时间
@ -295,6 +298,8 @@ class CtaLineBar(object):
self.param_list.append('para_ema1_len') # 三条EMA均线 self.param_list.append('para_ema1_len') # 三条EMA均线
self.param_list.append('para_ema2_len') self.param_list.append('para_ema2_len')
self.param_list.append('para_ema3_len') self.param_list.append('para_ema3_len')
self.param_list.append('para_ema4_len')
self.param_list.append('para_ema5_len')
self.param_list.append('para_dmi_len') self.param_list.append('para_dmi_len')
self.param_list.append('para_dmi_max') self.param_list.append('para_dmi_max')
@ -365,6 +370,7 @@ class CtaLineBar(object):
self.param_list.append('para_bd_len') self.param_list.append('para_bd_len')
self.param_list.append('para_active_chanlun') # 激活缠论 self.param_list.append('para_active_chanlun') # 激活缠论
self.param_list.append('para_active_chan_xt') # 激活缠论的形态分析
def init_properties(self): def init_properties(self):
""" """
@ -417,6 +423,8 @@ class CtaLineBar(object):
self.para_ema1_len = 0 # 13 # 第一根EMA均线的周期长度 self.para_ema1_len = 0 # 13 # 第一根EMA均线的周期长度
self.para_ema2_len = 0 # 21 # 第二根EMA均线的周期长度 self.para_ema2_len = 0 # 21 # 第二根EMA均线的周期长度
self.para_ema3_len = 0 # 120 # 第三根EMA均线的周期长度 self.para_ema3_len = 0 # 120 # 第三根EMA均线的周期长度
self.para_ema4_len = 0 # 120 # 第四根EMA均线的周期长度
self.para_ema5_len = 0 # 120 # 第五根EMA均线的周期长度
self.para_dmi_len = 0 # 14 # DMI的计算周期 self.para_dmi_len = 0 # 14 # DMI的计算周期
self.para_dmi_max = 0 # 30 # Dpi和Mdi的突破阈值 self.para_dmi_max = 0 # 30 # Dpi和Mdi的突破阈值
@ -538,10 +546,14 @@ class CtaLineBar(object):
self.line_ema1 = [] # K线的EMA1均线周期是para_ema1_len1不包含当前bar self.line_ema1 = [] # K线的EMA1均线周期是para_ema1_len1不包含当前bar
self.line_ema2 = [] # K线的EMA2均线周期是para_ema1_len2不包含当前bar self.line_ema2 = [] # K线的EMA2均线周期是para_ema1_len2不包含当前bar
self.line_ema3 = [] # K线的EMA3均线周期是para_ema1_len3不包含当前bar self.line_ema3 = [] # K线的EMA3均线周期是para_ema1_len3不包含当前bar
self.line_ema4 = [] # K线的EMA4均线周期是para_ema1_len4不包含当前bar
self.line_ema5 = [] # K线的EMA5均线周期是para_ema1_len5不包含当前bar
self._rt_ema1 = None # K线的实时EMA(para_ema1_len) self._rt_ema1 = None # K线的实时EMA(para_ema1_len)
self._rt_ema2 = None # K线的实时EMA(para_ema2_len) self._rt_ema2 = None # K线的实时EMA(para_ema2_len)
self._rt_ema3 = None # K线的实时EMA(para_ema3_len) self._rt_ema3 = None # K线的实时EMA(para_ema3_len)
self._rt_ema4 = None # K线的实时EMA(para_ema4_len)
self._rt_ema5 = None # K线的实时EMA(para_ema5_len)
# K线的DMI( PdiMdiADXAdxr) 计算数据 # K线的DMI( PdiMdiADXAdxr) 计算数据
self.cur_pdi = 0 # bar内的升动向指标即做多的比率 self.cur_pdi = 0 # bar内的升动向指标即做多的比率
@ -793,6 +805,14 @@ class CtaLineBar(object):
self._bi_zs_list = [] # 笔中枢列表 self._bi_zs_list = [] # 笔中枢列表
self._duan_list = [] # 段列表 self._duan_list = [] # 段列表
self._duan_zs_list = [] # 段中枢列表 self._duan_zs_list = [] # 段中枢列表
self.para_active_chan_xt = False # 是否激活czsc缠论形态识别
self.xt_3_signals = [] # czsc 三笔信号列表 {'bi_start'最后一笔开始,'bi_end'最后一笔结束,'signal'}
self.xt_5_signals = [] # czsc 五笔信号列表 {'bi_start'最后一笔开始,'bi_end'最后一笔结束,'signal'}
self.xt_7_signals = [] # czsc 七笔信号列表 {'bi_start'最后一笔开始,'bi_end'最后一笔结束,'signal'}
self.xt_9_signals = [] # czsc 九笔信号列表 {'bi_start'最后一笔开始,'bi_end'最后一笔结束,'signal'}
self.xt_11_signals = [] # czsc 11笔信号列表 {'bi_start'最后一笔开始,'bi_end'最后一笔结束,'signal'}
self.xt_13_signals = [] # czsc 13笔信号列表 {'bi_start'最后一笔开始,'bi_end'最后一笔结束,'signal'}
self.xt_2nd_signals = [] # 趋势背驰2买或趋势背驰2卖信号
def set_params(self, setting: dict = {}): def set_params(self, setting: dict = {}):
"""设置参数""" """设置参数"""
@ -828,7 +848,7 @@ class CtaLineBar(object):
return return
self.cur_datetime = tick.datetime self.cur_datetime = tick.datetime
self.cur_tick = copy.copy(tick) self.cur_tick = tick #copy.copy(tick)
# 兼容 标准套利合约它没有last_price # 兼容 标准套利合约它没有last_price
if self.cur_tick.last_price is None or self.cur_tick.last_price == 0: if self.cur_tick.last_price is None or self.cur_tick.last_price == 0:
@ -842,7 +862,7 @@ class CtaLineBar(object):
self.cur_price = self.cur_tick.last_price self.cur_price = self.cur_tick.last_price
# 3.生成x K线若形成新Bar则触发OnBar事件 # 3.生成x K线若形成新Bar则触发OnBar事件
self.generate_bar(copy.copy(self.cur_tick)) self.generate_bar(self.cur_tick) # copy.copy(self.cur_tick)
# 更新curPeriod的Highlow # 更新curPeriod的Highlow
if self.cur_period is not None: if self.cur_period is not None:
@ -864,8 +884,8 @@ class CtaLineBar(object):
self.cur_datetime = bar.datetime + timedelta(minutes=bar_freq) self.cur_datetime = bar.datetime + timedelta(minutes=bar_freq)
if self.bar_len == 0: if self.bar_len == 0:
new_bar = copy.deepcopy(bar) #new_bar = copy.deepcopy(bar)
self.line_bar.append(new_bar) self.line_bar.append(bar)
self.cur_trading_day = bar.trading_day self.cur_trading_day = bar.trading_day
self.on_bar(bar) self.on_bar(bar)
return return
@ -910,8 +930,8 @@ class CtaLineBar(object):
if is_new_bar: if is_new_bar:
# 添加新的bar # 添加新的bar
new_bar = copy.deepcopy(bar) #new_bar = copy.deepcopy(bar)
self.line_bar.append(new_bar) self.line_bar.append(bar) # new_bar
# 将上一个Bar推送至OnBar事件 # 将上一个Bar推送至OnBar事件
self.on_bar(lastBar) self.on_bar(lastBar)
@ -1008,6 +1028,9 @@ class CtaLineBar(object):
# 输出缠论=》csv文件 # 输出缠论=》csv文件
self.export_chan() self.export_chan()
# 识别缠论分笔形态
self.update_chan_xt()
# 回调上层调用者,将合成的 x分钟bar回调给策略 def on_bar_x(self, bar: BarData):函数 # 回调上层调用者,将合成的 x分钟bar回调给策略 def on_bar_x(self, bar: BarData):函数
if self.cb_on_bar: if self.cb_on_bar:
self.cb_on_bar(bar=bar) self.cb_on_bar(bar=bar)
@ -1121,6 +1144,12 @@ class CtaLineBar(object):
if self.para_ema3_len > 0 and len(self.line_ema3) > 0: if self.para_ema3_len > 0 and len(self.line_ema3) > 0:
msg = msg + u',EMA({0}):{1}'.format(self.para_ema3_len, self.line_ema3[-1]) msg = msg + u',EMA({0}):{1}'.format(self.para_ema3_len, self.line_ema3[-1])
if self.para_ema4_len > 0 and len(self.line_ema4) > 0:
msg = msg + u',EMA({0}):{1}'.format(self.para_ema4_len, self.line_ema4[-1])
if self.para_ema5_len > 0 and len(self.line_ema5) > 0:
msg = msg + u',EMA({0}):{1}'.format(self.para_ema5_len, self.line_ema5[-1])
if self.para_dmi_len > 0 and len(self.line_pdi) > 0: if self.para_dmi_len > 0 and len(self.line_pdi) > 0:
msg = msg + u',Pdi:{1};Mdi:{1};Adx:{2}'.format(self.line_pdi[-1], self.line_mdi[-1], self.line_adx[-1]) msg = msg + u',Pdi:{1};Mdi:{1};Adx:{2}'.format(self.line_pdi[-1], self.line_mdi[-1], self.line_adx[-1])
@ -2506,13 +2535,16 @@ class CtaLineBar(object):
def __count_ema(self): def __count_ema(self):
"""计算K线的EMA1 和EMA2""" """计算K线的EMA1 和EMA2"""
if not (self.para_ema1_len > 0 or self.para_ema2_len > 0 or self.para_ema3_len > 0): # 不计算 if not (self.para_ema1_len > 0 or self.para_ema2_len > 0 or self.para_ema3_len > 0
or self.para_ema4_len > 0 or self.para_ema5_len > 0): # 不计算
return return
ema1_data_len = min(self.para_ema1_len * 4, self.para_ema1_len + 40) if self.para_ema1_len > 0 else 0 ema1_data_len = min(self.para_ema1_len * 4, self.para_ema1_len + 40) if self.para_ema1_len > 0 else 0
ema2_data_len = min(self.para_ema2_len * 4, self.para_ema2_len + 40) if self.para_ema2_len > 0 else 0 ema2_data_len = min(self.para_ema2_len * 4, self.para_ema2_len + 40) if self.para_ema2_len > 0 else 0
ema3_data_len = min(self.para_ema3_len * 4, self.para_ema3_len + 40) if self.para_ema3_len > 0 else 0 ema3_data_len = min(self.para_ema3_len * 4, self.para_ema3_len + 40) if self.para_ema3_len > 0 else 0
max_data_len = max(ema1_data_len, ema2_data_len, ema3_data_len) ema4_data_len = min(self.para_ema4_len * 4, self.para_ema4_len + 40) if self.para_ema4_len > 0 else 0
ema5_data_len = min(self.para_ema5_len * 4, self.para_ema5_len + 40) if self.para_ema5_len > 0 else 0
max_data_len = max(ema1_data_len, ema2_data_len, ema3_data_len, ema4_data_len, ema5_data_len)
# 1、lineBar满足长度才执行计算 # 1、lineBar满足长度才执行计算
if self.bar_len < max_data_len: if self.bar_len < max_data_len:
self.write_log(u'数据未充分,当前Bar数据数量{0}计算EMA需要{1}'. self.write_log(u'数据未充分,当前Bar数据数量{0}计算EMA需要{1}'.
@ -2524,7 +2556,7 @@ class CtaLineBar(object):
count_len = min(self.para_ema1_len, self.bar_len - 1) count_len = min(self.para_ema1_len, self.bar_len - 1)
# 3、获取前InputN周期(不包含当前周期的K线 # 3、获取前InputN周期(不包含当前周期的K线
barEma1 = ta.EMA(self.close_array[-ema1_data_len:], count_len)[-1] barEma1 = ta.EMA(self.close_array[-self.para_ema1_len * 4:], count_len)[-1]
if np.isnan(barEma1): if np.isnan(barEma1):
return return
barEma1 = round(float(barEma1), self.round_n) barEma1 = round(float(barEma1), self.round_n)
@ -2539,7 +2571,7 @@ class CtaLineBar(object):
# 3、获取前InputN周期(不包含当前周期)的自适应均线 # 3、获取前InputN周期(不包含当前周期)的自适应均线
barEma2 = ta.EMA(self.close_array[-ema2_data_len:], count_len)[-1] barEma2 = ta.EMA(self.close_array[-self.para_ema2_len * 4:], count_len)[-1]
if np.isnan(barEma2): if np.isnan(barEma2):
return return
barEma2 = round(float(barEma2), self.round_n) barEma2 = round(float(barEma2), self.round_n)
@ -2553,7 +2585,7 @@ class CtaLineBar(object):
count_len = min(self.bar_len - 1, self.para_ema3_len) count_len = min(self.bar_len - 1, self.para_ema3_len)
# 3、获取前InputN周期(不包含当前周期)的自适应均线 # 3、获取前InputN周期(不包含当前周期)的自适应均线
barEma3 = ta.EMA(self.close_array[-ema3_data_len:], count_len)[-1] barEma3 = ta.EMA(self.close_array[-self.para_ema3_len * 4:], count_len)[-1]
if np.isnan(barEma3): if np.isnan(barEma3):
return return
barEma3 = round(float(barEma3), self.round_n) barEma3 = round(float(barEma3), self.round_n)
@ -2562,16 +2594,47 @@ class CtaLineBar(object):
del self.line_ema3[0] del self.line_ema3[0]
self.line_ema3.append(barEma3) self.line_ema3.append(barEma3)
# 计算第四条EMA均线
if self.para_ema4_len > 0:
count_len = min(self.bar_len - 1, self.para_ema4_len)
# 3、获取前InputN周期(不包含当前周期)的自适应均线
barEma4 = ta.EMA(self.close_array[-self.para_ema4_len * 4:], count_len)[-1]
if np.isnan(barEma4):
return
barEma4 = round(float(barEma4), self.round_n)
if len(self.line_ema4) > self.max_hold_bars:
del self.line_ema4[0]
self.line_ema4.append(barEma4)
# 计算第五条EMA均线
if self.para_ema5_len > 0:
count_len = min(self.bar_len - 1, self.para_ema5_len)
# 3、获取前InputN周期(不包含当前周期)的自适应均线
barEma5 = ta.EMA(self.close_array[-self.para_ema5_len * 4:], count_len)[-1]
if np.isnan(barEma5):
return
barEma5 = round(float(barEma5), self.round_n)
if len(self.line_ema5) > self.max_hold_bars:
del self.line_ema5[0]
self.line_ema5.append(barEma5)
def rt_count_ema(self): def rt_count_ema(self):
"""计算K线的EMA1 和EMA2""" """计算K线的EMA1 和EMA2"""
if not (self.para_ema1_len > 0 or self.para_ema2_len > 0 or self.para_ema3_len > 0): # 不计算 if not (self.para_ema1_len > 0 or self.para_ema2_len > 0 or self.para_ema3_len > 0
or self.para_ema4_len > 0 or self.para_ema5_len > 0): # 不计算
return return
ema1_data_len = min(self.para_ema1_len * 4, self.para_ema1_len + 40) if self.para_ema1_len > 0 else 0 ema1_data_len = min(self.para_ema1_len * 4, self.para_ema1_len + 40) if self.para_ema1_len > 0 else 0
ema2_data_len = min(self.para_ema2_len * 4, self.para_ema2_len + 40) if self.para_ema2_len > 0 else 0 ema2_data_len = min(self.para_ema2_len * 4, self.para_ema2_len + 40) if self.para_ema2_len > 0 else 0
ema3_data_len = min(self.para_ema3_len * 4, self.para_ema3_len + 40) if self.para_ema3_len > 0 else 0 ema3_data_len = min(self.para_ema3_len * 4, self.para_ema3_len + 40) if self.para_ema3_len > 0 else 0
max_data_len = max(ema1_data_len, ema2_data_len, ema3_data_len) ema4_data_len = min(self.para_ema4_len * 4, self.para_ema4_len + 40) if self.para_ema4_len > 0 else 0
ema5_data_len = min(self.para_ema5_len * 4, self.para_ema5_len + 40) if self.para_ema5_len > 0 else 0
max_data_len = max(ema1_data_len, ema2_data_len, ema3_data_len, ema4_data_len, ema5_data_len)
# 1、lineBar满足长度才执行计算 # 1、lineBar满足长度才执行计算
if self.bar_len < max_data_len: if self.bar_len < max_data_len:
return return
@ -2581,7 +2644,7 @@ class CtaLineBar(object):
count_len = min(self.para_ema1_len, self.bar_len) count_len = min(self.para_ema1_len, self.bar_len)
# 3、获取前InputN周期(不包含当前周期的K线 # 3、获取前InputN周期(不包含当前周期的K线
barEma1 = ta.EMA(np.append(self.close_array[-ema1_data_len:], [self.cur_price]), count_len)[-1] barEma1 = ta.EMA(np.append(self.close_array[-self.para_ema1_len * 4:], [self.cur_price]), count_len)[-1]
if np.isnan(barEma1): if np.isnan(barEma1):
return return
self._rt_ema1 = round(float(barEma1), self.round_n) self._rt_ema1 = round(float(barEma1), self.round_n)
@ -2592,7 +2655,7 @@ class CtaLineBar(object):
# 3、获取前InputN周期(不包含当前周期)的自适应均线 # 3、获取前InputN周期(不包含当前周期)的自适应均线
barEma2 = ta.EMA(np.append(self.close_array[-ema2_data_len:], [self.cur_price]), count_len)[-1] barEma2 = ta.EMA(np.append(self.close_array[-self.para_ema2_len * 4:], [self.cur_price]), count_len)[-1]
if np.isnan(barEma2): if np.isnan(barEma2):
return return
self._rt_ema2 = round(float(barEma2), self.round_n) self._rt_ema2 = round(float(barEma2), self.round_n)
@ -2602,11 +2665,31 @@ class CtaLineBar(object):
count_len = min(self.bar_len, self.para_ema3_len) count_len = min(self.bar_len, self.para_ema3_len)
# 3、获取前InputN周期(不包含当前周期)的自适应均线 # 3、获取前InputN周期(不包含当前周期)的自适应均线
barEma3 = ta.EMA(np.append(self.close_array[-ema3_data_len:], [self.cur_price]), count_len)[-1] barEma3 = ta.EMA(np.append(self.close_array[-self.para_ema3_len * 4:], [self.cur_price]), count_len)[-1]
if np.isnan(barEma3): if np.isnan(barEma3):
return return
self._rt_ema3 = round(float(barEma3), self.round_n) self._rt_ema3 = round(float(barEma3), self.round_n)
# 计算第四条EMA均线
if self.para_ema4_len > 0:
count_len = min(self.bar_len, self.para_ema4_len)
# 3、获取前InputN周期(不包含当前周期)的自适应均线
barEma4 = ta.EMA(np.append(self.close_array[-self.para_ema4_len * 4:], [self.cur_price]), count_len)[-1]
if np.isnan(barEma4):
return
self._rt_ema4 = round(float(barEma4), self.round_n)
# 计算第五条EMA均线
if self.para_ema5_len > 0:
count_len = min(self.bar_len, self.para_ema5_len)
# 3、获取前InputN周期(不包含当前周期)的自适应均线
barEma5 = ta.EMA(np.append(self.close_array[-self.para_ema5_len * 4:], [self.cur_price]), count_len)[-1]
if np.isnan(barEma5):
return
self._rt_ema5 = round(float(barEma5), self.round_n)
@property @property
def rt_ema1(self): def rt_ema1(self):
self.check_rt_funcs(self.rt_count_ema) self.check_rt_funcs(self.rt_count_ema)
@ -2628,6 +2711,20 @@ class CtaLineBar(object):
return self.line_ema3[-1] return self.line_ema3[-1]
return self._rt_ema3 return self._rt_ema3
@property
def rt_ema4(self):
self.check_rt_funcs(self.rt_count_ema)
if self._rt_ema4 is None and len(self.line_ema4) > 0:
return self.line_ema4[-1]
return self._rt_ema4
@property
def rt_ema5(self):
self.check_rt_funcs(self.rt_count_ema)
if self._rt_ema5 is None and len(self.line_ema5) > 0:
return self.line_ema5[-1]
return self._rt_ema5
def __count_dmi(self): def __count_dmi(self):
"""计算K线的DMI数据和条件""" """计算K线的DMI数据和条件"""
@ -5806,7 +5903,7 @@ class CtaLineBar(object):
return False return False
# 当前段包含的分笔必须大于3 # 当前段包含的分笔必须大于3
if len(cur_duan.bi_list) < 3: if len(cur_duan.bi_list) <= 3:
return False return False
# 获取倒数第二根同向分笔的结束dif值或macd值 # 获取倒数第二根同向分笔的结束dif值或macd值
@ -6132,6 +6229,79 @@ class CtaLineBar(object):
return False return False
def update_chan_xt(self):
"""更新缠论形态"""
if not self.para_active_chan_xt:
return
bi_len = len(self.bi_list)
if bi_len < 3:
return
if self.cur_fenxing.is_rt:
return
bi_n = min(15, bi_len)
price = self.cur_bi.low if self.cur_bi.direction == -1 else self.cur_bi.high
for n in range(3, bi_n, 2):
# => 信号
if n == 3:
signal = check_chan_xt_three_bi(self, self.bi_list[-n:])
else:
signal = check_chan_xt(self, self.bi_list[-n:])
# => 信号列表
xt_signals = getattr(self, f'xt_{n}_signals')
if xt_signals is None:
continue
# => 上一信号
cur_signal = xt_signals[-1] if len(xt_signals) > 0 else None
# 不同笔开始时间
if cur_signal is None or cur_signal.get("start", "") != self.cur_bi.start:
# 新增
xt_signals.append({'start': self.cur_bi.start,
'end': self.cur_bi.end,
'price': price,
'signal': signal})
if len(xt_signals) > 200:
del xt_signals[0]
if cur_signal is not None and self.export_xt_filename :
self.append_data(
file_name=self.export_xt_filename.replace('_n_',f'_{n}_'),
dict_data=cur_signal,
field_names=["start", "end", "price", "signal"]
)
# 直接更新
else:
xt_signals[-1].update({'end': self.cur_bi.end, 'price': price,'signal': signal})
# 是否趋势二买
qsbc_2nd = ChanSignals.Other.value
if self.cur_bi.direction == -1:
if check_qsbc_2nd(big_kline=self, small_kline=None, signal_direction=Direction.LONG):
qsbc_2nd = ChanSignals.Q2L0.value
else:
if check_qsbc_2nd(big_kline=self, small_kline=None,signal_direction=Direction.SHORT):
qsbc_2nd = ChanSignals.Q2S0.value
cur_signal = self.xt_2nd_signals[-1] if len(self.xt_2nd_signals) > 0 else None
# 不同笔开始时间
if cur_signal is None or cur_signal.get("start", "") != self.cur_bi.start:
# 新增
self.xt_2nd_signals.append({'start': self.cur_bi.start,
'end': self.cur_bi.end,
'price': price,
'signal': qsbc_2nd})
if cur_signal and self.export_xt_filename:
self.append_data(
file_name=self.export_xt_filename.replace('_n_', f'_2nd_'),
dict_data=cur_signal,
field_names=["start", "end", "price", "signal"]
)
# 直接更新
else:
self.xt_2nd_signals[-1].update({'end': self.cur_bi.end, 'price': price, 'signal': qsbc_2nd})
def write_log(self, content): def write_log(self, content):
"""记录CTA日志""" """记录CTA日志"""
@ -6338,6 +6508,22 @@ class CtaLineBar(object):
'type': 'line' 'type': 'line'
} }
indicators.update({indicator.get('name'): copy.copy(indicator)}) indicators.update({indicator.get('name'): copy.copy(indicator)})
if isinstance(self.para_ema4_len, int) and self.para_ema4_len > 0:
indicator = {
'name': 'EMA{}'.format(self.para_ema4_len),
'attr_name': 'line_ema4',
'is_main': True,
'type': 'line'
}
indicators.update({indicator.get('name'): copy.copy(indicator)})
if isinstance(self.para_ema5_len, int) and self.para_ema5_len > 0:
indicator = {
'name': 'EMA{}'.format(self.para_ema5_len),
'attr_name': 'line_ema5',
'is_main': True,
'type': 'line'
}
indicators.update({indicator.get('name'): copy.copy(indicator)})
# MA 均线 (主图) # MA 均线 (主图)
if isinstance(self.para_ma1_len, int) and self.para_ma1_len > 0: if isinstance(self.para_ma1_len, int) and self.para_ma1_len > 0:
@ -6820,9 +7006,9 @@ class CtaMinuteBar(CtaLineBar):
is_new_bar = True is_new_bar = True
if is_new_bar: if is_new_bar:
new_bar = copy.deepcopy(bar) #new_bar = copy.deepcopy(bar)
# 添加新的bar # 添加新的bar
self.line_bar.append(new_bar) self.line_bar.append(bar) # new_bar
# 将上一个Bar推送至OnBar事件 # 将上一个Bar推送至OnBar事件
self.on_bar(lastBar) self.on_bar(lastBar)
else: else:
@ -7261,8 +7447,8 @@ class CtaDayBar(CtaLineBar):
bar_len = len(self.line_bar) bar_len = len(self.line_bar)
if bar_len == 0: if bar_len == 0:
new_bar = copy.deepcopy(bar) #new_bar = copy.deepcopy(bar)
self.line_bar.append(new_bar) self.line_bar.append(bar) # new_bar
self.cur_trading_day = bar.trading_day if bar.trading_day is not None else get_trading_date(bar.datetime) self.cur_trading_day = bar.trading_day if bar.trading_day is not None else get_trading_date(bar.datetime)
if bar_is_completed: if bar_is_completed:
self.on_bar(bar) self.on_bar(bar)
@ -7288,8 +7474,8 @@ class CtaDayBar(CtaLineBar):
if is_new_bar: if is_new_bar:
# 添加新的bar # 添加新的bar
new_bar = copy.deepcopy(bar) #new_bar = copy.deepcopy(bar)
self.line_bar.append(new_bar) self.line_bar.append(bar) # new_bar
# 将上一个Bar推送至OnBar事件 # 将上一个Bar推送至OnBar事件
self.on_bar(lastBar) self.on_bar(lastBar)
else: else:

View File

@ -1,6 +1,6 @@
# encoding: UTF-8 # encoding: UTF-8
# 周期定义CTA的五种周期及其周期变换矩阵 # 周期状态类定义CTA的多种周期状态及其状态变换矩阵
from enum import Enum from enum import Enum
from datetime import datetime from datetime import datetime
@ -9,8 +9,12 @@ from datetime import datetime
class Period(Enum): class Period(Enum):
INIT = u'初始状态' INIT = u'初始状态'
LONG = u'' LONG = u''
LONG_STOP = u'止涨'
SHORT = u'' SHORT = u''
SHORT_STOP = u'止跌'
SHOCK = u'震荡' SHOCK = u'震荡'
SHOCK_LONG = u'震荡偏多'
SHOCK_SHORT = u'震荡偏空'
LONG_EXTREME = u'极端多' LONG_EXTREME = u'极端多'
SHORT_EXTREME = u'极端空' SHORT_EXTREME = u'极端空'

View File

@ -4,7 +4,7 @@ import os
import json import json
from datetime import datetime from datetime import datetime
from collections import OrderedDict from collections import OrderedDict
from vnpy.component.base import CtaComponent from vnpy.component.base import CtaComponent, MyEncoder
from vnpy.trader.utility import get_folder_path from vnpy.trader.utility import get_folder_path
TNS_STATUS_OBSERVATE = 'observate' TNS_STATUS_OBSERVATE = 'observate'
@ -15,24 +15,6 @@ TNS_STATUS_CLOSED = 'closed'
import numpy as np import numpy as np
class MyEncoder(json.JSONEncoder):
"""
自定义转换器处理np,datetime等不能被json转换得问题
"""
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
elif isinstance(obj, datetime):
return obj.strftime('%Y-%m-%d %H:%M:%S')
else:
return super(MyEncoder, self).default(obj)
class CtaPolicy(CtaComponent): class CtaPolicy(CtaComponent):
""" """
策略的持久化Policy组件 策略的持久化Policy组件

View File

@ -4,15 +4,16 @@
from vnpy.trader.constant import ChanSignals, Direction from vnpy.trader.constant import ChanSignals, Direction
from vnpy.component.chanlun.pyChanlun import ChanBi, ChanDuan, ChanObject from vnpy.component.chanlun.pyChanlun import ChanBi, ChanDuan, ChanObject
from vnpy.component.cta_line_bar import CtaLineBar # from vnpy.component.cta_line_bar import CtaLineBar
from typing import List, Union from typing import List, Union
# 所有底背驰信号集合 # 所有底背驰信号集合
DI_BEICHI_SIGNALS = [ChanSignals.LA0.value, ChanSignals.LA1.value, ChanSignals.LA2.value, ChanSignals.LA3.value, DI_BEICHI_SIGNALS = [ChanSignals.LA0.value,
ChanSignals.LB0.value, ChanSignals.LB1.value, ChanSignals.LB2.value, ChanSignals.LB3.value] ChanSignals.LB0.value]
# 所有顶背驰信号集合 # 所有顶背驰信号集合
DING_BEICHI_SIGNALS = [ChanSignals.SA0.value, ChanSignals.SA1.value, ChanSignals.SA2.value, ChanSignals.SA3.value, DING_BEICHI_SIGNALS = [ChanSignals.SA0.value,
ChanSignals.SB0.value, ChanSignals.SB1.value, ChanSignals.SB2.value, ChanSignals.SB3.value] ChanSignals.SB0.value]
def duan_bi_is_end(duan: ChanDuan, direction: Direction) -> bool: def duan_bi_is_end(duan: ChanDuan, direction: Direction) -> bool:
@ -37,7 +38,7 @@ def duan_bi_is_end(duan: ChanDuan, direction: Direction) -> bool:
return False return False
def check_duan_not_rt(kline: CtaLineBar, direction: Direction) -> bool: def check_duan_not_rt(kline, direction: Direction) -> bool:
""" """
检查某一个K线当前线段是否非实时 检查某一个K线当前线段是否非实时
:param kline: :param kline:
@ -58,7 +59,7 @@ def check_duan_not_rt(kline: CtaLineBar, direction: Direction) -> bool:
return True return True
def check_bi_not_rt(kline: CtaLineBar, direction: Direction) -> bool: def check_bi_not_rt(kline, direction: Direction) -> bool:
""" """
检查某一个K线当前分笔是否非实时并符合判断方向 检查某一个K线当前分笔是否非实时并符合判断方向
:param kline: :param kline:
@ -83,9 +84,9 @@ def check_bi_not_rt(kline: CtaLineBar, direction: Direction) -> bool:
if direction == 1: if direction == 1:
# 判断还没走完的bar是否满足顶分型 # 判断还没走完的bar是否满足顶分型
if float(kline.cur_fenxing.high) == float(kline.high_array[-1]) \ if float(kline.cur_fenxing.high) == float(kline.high_array[-1]) \
and kline.cur_fenxing.index == kline.index_list[-1] \ and kline.cur_fenxing.index == kline.index_list[-1] \
and kline.line_bar[-1].datetime.strftime('%Y-%m-%d %H:%M:%S') > kline.cur_fenxing.index\ and kline.line_bar[-1].datetime.strftime('%Y-%m-%d %H:%M:%S') > kline.cur_fenxing.index \
and kline.line_bar[-1].high_price < float(kline.cur_fenxing.high) \ and kline.line_bar[-1].high_price < float(kline.cur_fenxing.high) \
and kline.line_bar[-1].low_price < kline.line_bar[-2].low_price: and kline.line_bar[-1].low_price < kline.line_bar[-2].low_price:
return True return True
@ -103,7 +104,7 @@ def check_bi_not_rt(kline: CtaLineBar, direction: Direction) -> bool:
return True return True
def check_fx_power(kline: CtaLineBar, direction: Direction) -> str: def check_fx_power(kline, direction: Direction) -> str:
""" """
获取分型强弱 获取分型强弱
:param kline: 本级别K线 :param kline: 本级别K线
@ -165,7 +166,7 @@ def check_fx_power(kline: CtaLineBar, direction: Direction) -> str:
return ret return ret
def check_chan_xt(kline: CtaLineBar, bi_list: List[ChanObject]) -> str: def check_chan_xt(kline, bi_list: List[ChanObject]) -> str:
""" """
获取缠论得形态 获取缠论得形态
如果提供得是段内得bi_list一般可以算出该线段是否有背驰 如果提供得是段内得bi_list一般可以算出该线段是否有背驰
@ -189,12 +190,12 @@ def check_chan_xt(kline: CtaLineBar, bi_list: List[ChanObject]) -> str:
return v return v
def check_chan_xt_three_bi(kline: CtaLineBar, bi_list: List[ChanObject]): def check_chan_xt_three_bi(kline, bi_list: List[ChanObject]):
""" """
获取指定3分笔得形态 获取指定3分笔得形态
含有三笔 含有三笔
:param kline: :param kline: ctaLineBar对象
:param bi_list: :param bi_list: 笔列表
:return: :return:
""" """
v = ChanSignals.Other.value v = ChanSignals.Other.value
@ -207,64 +208,148 @@ def check_chan_xt_three_bi(kline: CtaLineBar, bi_list: List[ChanObject]):
# 最后一笔是下跌 # 最后一笔是下跌
if bi_3.direction == -1: if bi_3.direction == -1:
# X3LA0~向下不重合 # X3LA0~向下不重合
# ^
# / \
# / \
# /
# \ /
# \ /
# v
if bi_3.low > bi_1.high: if bi_3.low > bi_1.high:
v = ChanSignals.X3LA0.value v = ChanSignals.X3LA0.value
# X3LB0~向下奔走型中枢 # X3LB0~向下奔走型
# ^
# / \
# / \
# \ / \
# \ /
# \ /
# v
if bi_2.low < bi_3.low < bi_1.high < bi_2.high: if bi_2.low < bi_3.low < bi_1.high < bi_2.high:
v = ChanSignals.X3LB0.value v = ChanSignals.X3LB0.value
# X3LC0~向下三角收敛中枢 # X3LC0~向下收敛
# \
# \ ^
# \ / \
# \ / \
# \ /
# \ /
# v
if bi_1.high > bi_3.high and bi_1.low < bi_3.low: if bi_1.high > bi_3.high and bi_1.low < bi_3.low:
v = ChanSignals.X3LC0.value v = ChanSignals.X3LC0.value
# 向下三角扩张中枢 # X3LD0~向下扩张
# ^
# / \
# \ / \
# \ / \
# v \
# \
if bi_1.high < bi_3.high and bi_1.low > bi_3.low: if bi_1.high < bi_3.high and bi_1.low > bi_3.low:
v = ChanSignals.X3LD0.value v = ChanSignals.X3LD0.value
# X3LE0~向下盘背中枢, X3LF0~向下无背中枢 # X3LE0~向下盘背 X3LF0~向下无背
if bi_3.low < bi_1.low and bi_3.high < bi_1.high: if bi_3.low < bi_1.low and bi_3.high < bi_1.high:
if bi_3.height < bi_1.height: if bi_3.height < bi_1.height:
# X3LE0~向下盘背中枢 # X3LE0~向下盘背
# \
# \
# \ ^
# \ / \
# \ / \
# v \
# \
v = ChanSignals.X3LE0.value v = ChanSignals.X3LE0.value
else: else:
# X3LF0~向下无背中枢 # X3LF0~向下无背中枢
# \
# \ ^
# \ / \
# \ / \
# v \
# \
# \
v = ChanSignals.X3LF0.value v = ChanSignals.X3LF0.value
# 上涨线段 # 上涨线段
elif bi_3.direction == 1: elif bi_3.direction == 1:
# X3SA0~向上不重合 # X3SA0~向上不重合
if bi_3.high > bi_1.low: # ^
# / \
# / \
# \
# \ /
# \ /
# v
if bi_3.high < bi_1.low:
v = ChanSignals.X3SA0.value v = ChanSignals.X3SA0.value
# X3SB0~向上奔走型中枢 # X3SB0~向上奔走型
# ^
# / \
# / \ /
# / \ /
# \ /
# v
if bi_2.low < bi_1.low < bi_3.high < bi_2.high: if bi_2.low < bi_1.low < bi_3.high < bi_2.high:
v = ChanSignals.X3SB0.value v = ChanSignals.X3SB0.value
# X3SC0~向上三角收敛中枢 # X3SC0~向上收敛
# ^
# / \
# / \ /
# / \ /
# / v
# /
if bi_1.high > bi_3.high and bi_1.low < bi_3.low: if bi_1.high > bi_3.high and bi_1.low < bi_3.low:
v = ChanSignals.X3SC0.value v = ChanSignals.X3SC0.value
# X3SD0~向上三角扩张中枢 # X3SD0~向上扩张
# /
# ^ /
# / \ /
# / \ /
# / \ /
# v
if bi_1.high < bi_3.high and bi_1.low > bi_3.low: if bi_1.high < bi_3.high and bi_1.low > bi_3.low:
v = ChanSignals.X3SD0.value v = ChanSignals.X3SD0.value
# X3SE0~向上盘背中枢X3SF0~向上无背中枢
# X3SE0~向上盘背X3SF0~向上无背
if bi_3.low > bi_1.low and bi_3.high > bi_1.high: if bi_3.low > bi_1.low and bi_3.high > bi_1.high:
if bi_3.height < bi_1.height: if bi_3.height < bi_1.height:
# X3SE0~向上盘背中枢 # X3SE0~向上盘背
# /
# ^ /
# / \ /
# / \ /
# / \ /
# / v
# /
# /
v = ChanSignals.X3SE0.value v = ChanSignals.X3SE0.value
else: else:
# X3SF0~向上无背中枢 # X3SF0~向上无背
# /
# /
# ^ /
# / \ /
# / \ /
# / \ /
# / v
# /
v = ChanSignals.X3SF0.value v = ChanSignals.X3SF0.value
return v return v
def check_chan_xt_five_bi(kline: CtaLineBar, bi_list: List[ChanObject]): def check_chan_xt_five_bi(kline, bi_list: List[ChanObject]):
"""识别当前5笔形态 """识别当前5笔形态
:param cur_duan: 当前线段 :param kline: ctaLineBar对象
:return: str :param bi_list: 笔列表
""" :return: str
"""
v = ChanSignals.Other.value v = ChanSignals.Other.value
if len(bi_list) != 5: if len(bi_list) != 5:
@ -282,77 +367,77 @@ def check_chan_xt_five_bi(kline: CtaLineBar, bi_list: List[ChanObject]):
# aAb式底背驰 # aAb式底背驰
if min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) and max_high == bi_1.high and bi_5.height < bi_1.height: if min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) and max_high == bi_1.high and bi_5.height < bi_1.height:
if (min_low == bi_3.low and bi_5.low < bi_1.low) or (min_low == bi_5.low): if (min_low == bi_3.low and bi_5.low < bi_1.low) or (min_low == bi_5.low):
v = ChanSignals.LA0.value return ChanSignals.LA0.value # "底背驰”五笔aAb式
# 类趋势底背驰( 笔5 的强度比笔1、笔3低 # 类趋势底背驰( 笔5 的强度比笔1、笔3低
if max_high == bi_1.high and min_low == bi_5.low and bi_4.high < bi_2.low \ if max_high == bi_1.high and min_low == bi_5.low and bi_4.high < bi_2.low \
and bi_5.height < max(bi_3.height, bi_1.height) \ and bi_5.height < max(bi_3.height, bi_1.height) \
and bi_5.atan < max(bi_3.atan, bi_1.atan): and bi_5.atan < max(bi_3.atan, bi_1.atan):
v = ChanSignals.LA0.value return ChanSignals.LA0.value # "底背驰" 五笔类趋势
# 上颈线突破 # 上颈线突破
if (min_low == bi_1.low and bi_5.high > min(bi_1.high, bi_2.high) > bi_5.low > bi_1.low) \ if (min_low == bi_1.low and bi_5.high > min(bi_1.high, bi_2.high) > bi_5.low > bi_1.low) \
or (min_low == bi_3.low and bi_5.high > bi_3.high > bi_5.low > bi_3.low): or (min_low == bi_3.low and bi_5.high > bi_3.high > bi_5.low > bi_3.low):
v = ChanSignals.LG0.value return ChanSignals.LG0.value # 上颈线突破 五笔
# 五笔三买要求bi_5.high是最高点, 或者bi_4.height超过笔2、笔3两倍 # 五笔三买要求bi_5.high是最高点, 或者bi_4.height超过笔2、笔3两倍
if max(bi_1.low, bi_3.low) < min(bi_1.high, bi_3.high) < bi_5.low: if min_low < max(bi_1.low, bi_3.low) < min(bi_1.high, bi_3.high) < bi_5.low:
if bi_5.high == max_high: if bi_5.high == max_high:
v = ChanSignals.LI0.value v = ChanSignals.LI0.value # 类三买, 五笔
elif bi_4.low == min_low and bi_1.high == max_high \ elif bi_3.low == min_low and bi_1.high == max_high \
and bi_4.height > max(bi_1.height, bi_2.height, bi_3.height) \ and bi_4.height > max(bi_1.height, bi_2.height, bi_3.height) \
and bi_4.height > 2 * max(bi_2.height, bi_3.height): and bi_4.height > 2 * max(bi_2.height, bi_3.height):
v = ChanSignals.LI0.value v = ChanSignals.LI0.value # 类三买, 五笔
# 向上三角扩张中枢 # # 向上三角扩张中枢
if bi_1.high < bi_3.high < bi_5.high and bi_1.low > bi_3.low > bi_5.low: # if bi_1.high < bi_3.high < bi_5.high and bi_1.low > bi_3.low > bi_5.low:
v = ChanSignals.LJ0.value # v = ChanSignals.LJ0.value
#
# 向上三角收敛中枢 # # 向上三角收敛中枢
if bi_1.high > bi_3.high > bi_5.high and bi_1.low < bi_3.low < bi_5.low: # if bi_1.high > bi_3.high > bi_5.high and bi_1.low < bi_3.low < bi_5.low:
v = ChanSignals.LK0.value # v = ChanSignals.LK0.value
# 上涨线段,寻找顶背驰 # 上涨线段,寻找顶背驰
elif direction == 1: elif direction == 1:
# aAb式顶背驰 # aAb式顶背驰,类一卖
if min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) and min_low == bi_1.low and bi_5.height < bi_1.height: if min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) and min_low == bi_1.low and bi_5.height < bi_1.height:
if (max_high == bi_3.high and bi_5.high > bi_1.high) or (max_high == bi_5.high): if (max_high == bi_3.high and bi_5.high > bi_1.high) or (max_high == bi_5.high):
v = ChanSignals.SA0.value return ChanSignals.SA0.value # k3='基础形态', v1='顶背驰', v2='五笔aAb式'
# 类趋势顶背驰 # 类趋势顶背驰,类一卖
if min_low == bi_1.low and max_high == bi_5.high \ if min_low == bi_1.low and max_high == bi_5.high \
and bi_5.height < max(bi_1.height, bi_3.height) \ and bi_5.height < max(bi_1.height, bi_3.height) \
and bi_5.atan < max(bi_1.atan, bi_3.atan) \ and bi_5.atan < max(bi_1.atan, bi_3.atan) \
and bi_4.low > bi_2.high: and bi_4.low > bi_2.high:
v = ChanSignals.SA0.value return ChanSignals.SA0.value # k3='基础形态', v1='顶背驰', v2='五笔类趋势')
# 下颈线突破 # 下颈线突破
if (max_high == bi_1.high and bi_5.low < max(bi_1.low, bi_2.low) < bi_5.high < max_high) \ if (max_high == bi_1.high and bi_5.low < max(bi_1.low, bi_2.low) < bi_5.high < max_high) \
or (max_high == bi_3.high and bi_5.low < bi_3.low < bi_5.high < max_high): or (max_high == bi_3.high and bi_5.low < bi_3.low < bi_5.high < max_high):
v = ChanSignals.SG0.value return ChanSignals.SG0.value # k3='基础形态', v1='下颈线突破', v2='五笔')
# 五笔三卖要求bi_5.low是最低点中枢可能是1~3 # 五笔三卖要求bi_5.low是最低点中枢可能是1~3
if min(bi_1.high, bi_3.high) > max(bi_1.low, bi_3.low) > bi_5.high: if min(bi_1.high, bi_3.high) > max(bi_1.low, bi_3.low) > bi_5.high:
if bi_5.low == min_low: if bi_5.low == min_low:
v = ChanSignals.SI0.value return ChanSignals.SI0.value
elif bi_4.high == max_high and bi_1.low == min_low \ elif bi_3.high == max_high and bi_1.low == min_low \
and bi_4.height > max(bi_1.height, bi_2.height, bi_3.height)\ and bi_4.height > max(bi_1.height, bi_2.height, bi_3.height) \
and bi_4.height > 2 * max(bi_2.height,bi_3.height): and bi_4.height > 2 * max(bi_2.height, bi_3.height):
v = ChanSignals.SI0.value return ChanSignals.SI0.value # k3='基础形态', v1='类三卖', v2='五笔')
# elif bi_1.high == max_high and bi_1.low == min_low: # elif bi_1.high == max_high and bi_1.low == min_low:
# 向下三角扩张中枢 # # 向下三角扩张中枢
if bi_1.high < bi_3.high < bi_5.high and bi_1.low > bi_3.low > bi_5.low: # if bi_1.high < bi_3.high < bi_5.high and bi_1.low > bi_3.low > bi_5.low:
v = ChanSignals.SJ0.value # v = ChanSignals.SJ0.value
#
# 向下三角收敛中枢 # # 向下三角收敛中枢
if bi_1.high > bi_3.high > bi_5.high and bi_1.low < bi_3.low < bi_5.low: # if bi_1.high > bi_3.high > bi_5.high and bi_1.low < bi_3.low < bi_5.low:
v = ChanSignals.SK0.value # v = ChanSignals.SK0.value
return v return v
def check_chan_xt_seven_bi(kline: CtaLineBar, bi_list: List[ChanObject]): def check_chan_xt_seven_bi(kline, bi_list: List[ChanObject]):
""" """
识别当前7笔的形态 识别当前7笔的形态
:param cur_duan: :param cur_duan:
@ -371,80 +456,80 @@ def check_chan_xt_seven_bi(kline: CtaLineBar, bi_list: List[ChanObject]):
# aAbcd式底背驰, d.高度斜率 小于 b.高度斜率 # aAbcd式底背驰, d.高度斜率 小于 b.高度斜率
if min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) > bi_6.high \ if min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) > bi_6.high \
and bi_7.height < bi_5.height and bi_7.atan <= bi_5.atan: and bi_7.height < bi_5.height and bi_7.atan <= bi_5.atan:
v = ChanSignals.LA0.value v = ChanSignals.LA0.value # k3='基础形态', v1='底背驰', v2='七笔aAbcd式')
# abcAd式底背驰 # abcAd式底背驰
if bi_2.low > min(bi_4.high, bi_6.high) > max(bi_4.low, bi_6.low) \ if bi_2.low > min(bi_4.high, bi_6.high) > max(bi_4.low, bi_6.low) \
and bi_7.height < (bi_1.high - bi_3.low) \ and bi_7.height < (bi_1.high - bi_3.low) \
and bi_7.atan < (bi_1.atan + bi_3.atan) / 2: and bi_7.atan < (bi_1.atan + bi_3.atan) / 2:
v = ChanSignals.LA0.value v = ChanSignals.LA0.value # k3='基础形态', v1='底背驰', v2='七笔abcAd式')
# aAb式底背驰 # aAb式底背驰
if min(bi_2.high, bi_4.high, bi_6.high) > max(bi_2.low, bi_4.low, bi_6.low) \ if min(bi_2.high, bi_4.high, bi_6.high) > max(bi_2.low, bi_4.low, bi_6.low) \
and bi_7.height < bi_1.height and bi_7.atan <= bi_1.atan: and bi_7.height < bi_1.height and bi_7.atan <= bi_1.atan:
v = ChanSignals.LA0.value v = ChanSignals.LA0.value # k3='基础形态', v1='底背驰', v2='七笔aAb式'
# 类趋势底背驰 # 类趋势底背驰
if bi_2.low > bi_4.high and bi_4.low > bi_6.high \ if bi_2.low > bi_4.high and bi_4.low > bi_6.high \
and bi_7.height < max(bi_5.height, bi_3.height, bi_1.height)\ and bi_7.height < max(bi_5.height, bi_3.height, bi_1.height) \
and bi_7.atan < max(bi_5.atan, bi_3.atan, bi_1.atan): and bi_7.atan < max(bi_5.atan, bi_3.atan, bi_1.atan):
v = ChanSignals.LA0.value v = ChanSignals.LA0.value # k3='基础形态', v1='底背驰', v2='七笔类趋势'
# 向上中枢完成 # 向上中枢完成
if bi_4.low == min_low and min(bi_1.high, bi_3.high) > max(bi_1.low, bi_3.low) \ if bi_4.low == min_low and min(bi_1.high, bi_3.high) > max(bi_1.low, bi_3.low) \
and min(bi_5.high, bi_7.high) > max(bi_5.low, bi_7.low) \ and min(bi_5.high, bi_7.high) > max(bi_5.low, bi_7.low) \
and max(bi_4.high, bi_6.high) > min(bi_3.high, bi_4.high): and max(bi_4.high, bi_6.high) > min(bi_3.high, bi_4.high):
if max(bi_1.low, bi_3.low) < max(bi_5.high, bi_7.high): if max(bi_1.low, bi_3.low) < max(bi_5.high, bi_7.high):
v = ChanSignals.LH0.value v = ChanSignals.LH0.value # k3='基础形态', v1='向上中枢完成', v2='七笔')
# 七笔三买567回调 # 七笔三买567回调 1~3构成中枢最低点在1~3最高点在5~75~7的最低点大于1~3的最高点
if bi_5.high == max_high and bi_5.high > bi_7.high \ if bi_5.high == max_high and bi_5.high > bi_7.high \
and bi_5.low > bi_7.low > min(bi_1.high, bi_3.high) > max(bi_1.low, bi_3.low): and bi_5.low > bi_7.low > min(bi_1.high, bi_3.high) > max(bi_1.low, bi_3.low):
v = ChanSignals.LI0.value v = ChanSignals.LI0.value # k3='基础形态', v1='类三买', v2='七笔'
#
elif bi_7.direction == 1: elif bi_7.direction == 1:
# 顶背驰 # 顶背驰
if bi_1.low == min_low and bi_7.high == max_high: if bi_1.low == min_low and bi_7.high == max_high:
# aAbcd式顶背驰 # aAbcd式顶背驰
if bi_6.low > min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) \ if bi_6.low > min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) \
and bi_7.height < bi_5.height and bi_7.atan <= bi_5.atan: and bi_7.height < bi_5.height and bi_7.atan <= bi_5.atan:
v = ChanSignals.SA0.value v = ChanSignals.SA0.value # k3='基础形态', v1='顶背驰', v2='七笔aAbcd式'
# abcAd式顶背驰 # abcAd式顶背驰
if min(bi_4.high, bi_6.high) > max(bi_4.low, bi_6.low) > bi_2.high \ if min(bi_4.high, bi_6.high) > max(bi_4.low, bi_6.low) > bi_2.high \
and bi_7.height < (bi_3.high - bi_1.low) \ and bi_7.height < (bi_3.high - bi_1.low) \
and bi_7.atan < (bi_1.atan + bi_3.atan) / 2: and bi_7.atan < (bi_1.atan + bi_3.atan) / 2:
v = ChanSignals.SA0.value v = ChanSignals.SA0.value # k3='基础形态', v1='顶背驰', v2='七笔abcAd式'
# aAb式顶背驰 # aAb式顶背驰
if min(bi_2.high, bi_4.high, bi_6.high) > max(bi_2.low, bi_4.low, bi_6.low) \ if min(bi_2.high, bi_4.high, bi_6.high) > max(bi_2.low, bi_4.low, bi_6.low) \
and bi_7.height < bi_1.height and bi_7.atan <= bi_1.atan: and bi_7.height < bi_1.height and bi_7.atan <= bi_1.atan:
v = ChanSignals.SA0.value v = ChanSignals.SA0.value # k3='基础形态', v1='顶背驰', v2='七笔aAb式'
# 类趋势顶背驰 # 类趋势顶背驰
if bi_2.high < bi_4.low and bi_4.high < bi_6.low \ if bi_2.high < bi_4.low and bi_4.high < bi_6.low \
and bi_7.height < max(bi_5.height, bi_3.height, bi_1.height)\ and bi_7.height < max(bi_5.height, bi_3.height, bi_1.height) \
and bi_7.atan < max(bi_5.atan, bi_3.atan, bi_1.atan): and bi_7.atan < max(bi_5.atan, bi_3.atan, bi_1.atan):
v = ChanSignals.SA0.value v = ChanSignals.SA0.value # k3='基础形态', v1='顶背驰', v2='七笔类趋势'
# 向下中枢完成 # 向下中枢完成
if bi_4.high == max_high and min(bi_1.high, bi_3.high) > max(bi_1.low, bi_3.low) \ if bi_4.high == max_high and min(bi_1.high, bi_3.high) > max(bi_1.low, bi_3.low) \
and min(bi_5.high, bi_7.high) > max(bi_5.low, bi_7.low) \ and min(bi_5.high, bi_7.high) > max(bi_5.low, bi_7.low) \
and min(bi_4.low, bi_6.low) < max(bi_3.low, bi_4.low): and min(bi_4.low, bi_6.low) < max(bi_3.low, bi_4.low):
if min(bi_1.high, bi_3.high) > min(bi_5.low, bi_7.low): if min(bi_1.high, bi_3.high) > min(bi_5.low, bi_7.low):
v = ChanSignals.SH0.value v = ChanSignals.SH0.value # k3='基础形态', v1='向下中枢完成', v2='七笔'
# 七笔三卖567回调中枢可能在1~3 # 七笔三卖567回调 1~3构成中枢最高点在1~3最低点在5~75~7的最高点小于1~3的最低点
if bi_5.low == min_low and bi_5.low < bi_7.low \ if bi_5.low == min_low and bi_5.low < bi_7.low \
and min(bi_1.high, bi_3.high) > max(bi_1.low, bi_3.low) > bi_7.high > bi_5.high: and min(bi_1.high, bi_3.high) > max(bi_1.low, bi_3.low) > bi_7.high > bi_5.high:
v = ChanSignals.SI0.value v = ChanSignals.SI0.value # k3='基础形态', v1='类三卖', v2='七笔'
return v return v
def check_chan_xt_nine_bi(kline: CtaLineBar, bi_list: List[ChanObject]): def check_chan_xt_nine_bi(kline, bi_list: List[ChanObject]):
""" """
获取线段得形态9分笔 获取线段得买卖点9分笔
:param cur_duan: :param cur_duan:
:return: :return:
""" """
@ -460,72 +545,126 @@ def check_chan_xt_nine_bi(kline: CtaLineBar, bi_list: List[ChanObject]):
# 依据最后一笔得方向进行判断 # 依据最后一笔得方向进行判断
if direction == -1: if direction == -1:
if min_low == bi_9.low and max_high == bi_1.high: if min_low == bi_9.low and max_high == bi_1.high:
# aAbBc式底背驰 # aAb式类一买
if min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) > bi_6.high \
and min(bi_6.high, bi_8.high) > max(bi_6.low, bi_8.low) \
and min(bi_2.low, bi_4.low) > max(bi_6.high, bi_8.high) \
and bi_9.height < bi_5.height and bi_7.atan <= bi_5.atan:
v = ChanSignals.LA0.value
# aAb式底背驰
if min(bi_2.high, bi_4.high, bi_6.high, bi_8.high) > max(bi_2.low, bi_4.low, bi_6.low, bi_8.low) \ if min(bi_2.high, bi_4.high, bi_6.high, bi_8.high) > max(bi_2.low, bi_4.low, bi_6.low, bi_8.low) \
and bi_9.height < bi_1.height and bi_9.atan <= bi_1.atan \ and bi_9.height < bi_1.height and bi_9.atan <= bi_1.atan \
and bi_3.low >= bi_1.low and bi_7.high <= bi_9.high: and bi_3.low >= bi_1.low and bi_7.high <= bi_9.high:
v = ChanSignals.LA0.value return ChanSignals.Q1L0.value # k3='类买卖点', v1='类一买', v2='九笔aAb式'
# aAbcd式底背驰 # aAbcd式类一买
if min(bi_2.high, bi_4.high, bi_6.high) > max(bi_2.low, bi_4.low, bi_6.low) > bi_8.high \ if min(bi_2.high, bi_4.high, bi_6.high) > max(bi_2.low, bi_4.low, bi_6.low) > bi_8.high \
and bi_9.height < bi_7.height and bi_9.atan <= bi_7.atan: and bi_9.height < bi_7.height and bi_9.atan <= bi_7.atan:
v = ChanSignals.LA0.value return ChanSignals.Q1L0.value # k3='类买卖点', v1='类一买', v2='九笔aAbcd式'
# ABC式底背驰 # ABC式类一买
if bi_3.low < bi_1.low and bi_7.high > bi_9.high \ if bi_3.low < bi_1.low and bi_7.high > bi_9.high \
and min(bi_4.high, bi_6.high) > max(bi_4.low, bi_6.low) \ and min(bi_4.high, bi_6.high) > max(bi_4.low, bi_6.low) \
and (bi_1.high - bi_3.low) > (bi_7.high - bi_9.low): and (bi_1.high - bi_3.low) > (bi_7.high - bi_9.low):
v = ChanSignals.LA0.value return ChanSignals.Q1L0.value # k3='类买卖点', v1='类一买', v2='九笔ABC式'
# 九笔三买(789回调中枢可能在3~7内 # 类趋势一买
if min_low == bi_1.low and max_high == bi_9.high \ if bi_8.high < bi_6.low < bi_6.high < bi_4.high < bi_2.low \
and bi_9.low > min([x.high for x in [bi_3, bi_5, bi_7]]) > max([x.low for x in [bi_3, bi_5, bi_7]]): and bi_9.atan < max([bi_1.atan, bi_3.atan, bi_5.atan, bi_7.atan]):
v = ChanSignals.LI0.value return ChanSignals.Q1L0.value # k3='类买卖点', v1='类一买', v2='九笔类趋势'
# 9笔 aAbBc式类一买2~4构成中枢A6~8构成中枢B9背驰
if max_high == max(bi_1.high, bi_3.high) and min_low == bi_9.low \
and min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) > bi_6.high \
and min(bi_6.high, bi_8.high) > max(bi_6.low, bi_8.low) \
and min(bi_2.low, bi_4.low) > max(bi_6.high, bi_8.high) \
and bi_9.height < bi_5.height and bi_9.atan <= bi_5.atan:
return ChanSignals.Q1L0.value # k3='类买卖点', v1='类一买', v2='九笔aAb式')
# 九笔GG 类三买1357构成中枢最低点在3或5
if max_high == bi_9.high > bi_9.low \
> max([x.high for x in [bi_1, bi_3, bi_5, bi_7]]) \
> min([x.high for x in [bi_1, bi_3, bi_5, bi_7]]) \
> max([x.low for x in [bi_1, bi_3, bi_5, bi_7]]) \
> min([x.low for x in [bi_3, bi_5]]) == min_low:
return ChanSignals.Q3L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类三买', v2='九笔GG三买')
# 类三买357构成中枢8的力度小于29回调不跌破GG构成三买
if bi_8.height < bi_2.height and max_high == bi_9.high > bi_9.low \
> max([x.high for x in [bi_3, bi_5, bi_7]]) \
> min([x.high for x in [bi_3, bi_5, bi_7]]) \
> max([x.low for x in [bi_3, bi_5, bi_7]]) > bi_1.low == min_low:
return ChanSignals.Q3L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类三买', v2='九笔GG三买')
# # 九笔三买(789回调中枢可能在3~7内
# if min_low == bi_1.low and max_high == bi_9.high \
# and bi_9.low > min([x.high for x in [bi_3, bi_5, bi_7]]) > max([x.low for x in [bi_3, bi_5, bi_7]]):
# v = ChanSignals.Q3L0.value
if min_low == bi_5.low and max_high == bi_1.high and bi_4.high < bi_2.low: # 前五笔构成向下类趋势
zd = max([x.low for x in [bi_5, bi_7]])
zg = min([x.high for x in [bi_5, bi_7]])
gg = max([x.high for x in [bi_5, bi_7]])
if zg > zd and bi_8.high > gg: # 567构成中枢且8的高点大于gg
if bi_9.low > zg:
return ChanSignals.Q3L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类三买', v2='九笔ZG三买')
# 类二买
if bi_9.high > gg > zg > bi_9.low > zd:
return ChanSignals.Q2L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二买', v2='九笔')
elif direction == 1: elif direction == 1:
if max_high == bi_9.high and min_low == bi_1.low:
# aAbBc式顶背驰
if bi_6.low > min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) \
and min(bi_6.high, bi_8.high) > max(bi_6.low, bi_8.low) \
and max(bi_2.high, bi_4.high) < min(bi_6.low, bi_8.low) \
and bi_9.height < bi_5.height and bi_9.atan <= bi_5.atan:
v = ChanSignals.SA0.value
# aAb式顶背驰 # 倒9笔是最高点倒一笔是最低点
if max_high == bi_9.high and min_low == bi_1.low:
# aAb式类一卖
if min(bi_2.high, bi_4.high, bi_6.high, bi_8.high) > max(bi_2.low, bi_4.low, bi_6.low, bi_8.low) \ if min(bi_2.high, bi_4.high, bi_6.high, bi_8.high) > max(bi_2.low, bi_4.low, bi_6.low, bi_8.low) \
and bi_9.height < bi_1.height and bi_9.atan <= bi_1.atan \ and bi_9.height < bi_1.height and bi_9.atan <= bi_1.atan \
and bi_3.high <= bi_1.high and bi_7.low >= bi_9.low: and bi_3.high <= bi_1.high and bi_7.low >= bi_9.low:
v = ChanSignals.SA0.value return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2='九笔aAb式')
# aAbcd式顶背驰 # aAbcd式类一卖
if bi_8.low > min(bi_2.high, bi_4.high, bi_6.high) > max(bi_2.low, bi_4.low, bi_6.low) \ if bi_8.low > min(bi_2.high, bi_4.high, bi_6.high) > max(bi_2.low, bi_4.low, bi_6.low) \
and bi_9.height < bi_7.height and bi_9.atan <= bi_7.atan: and bi_9.height < bi_7.height and bi_9.atan <= bi_7.atan:
v = ChanSignals.SA0.value return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2='九笔aAbcd式')
# ABC式顶背驰 # ABC式类一卖
if bi_3.high > bi_1.high and bi_7.low < bi_9.low \ if bi_3.high > bi_1.high and bi_7.low < bi_9.low \
and min(bi_4.high, bi_6.high) > max(bi_4.low, bi_6.low) \ and min(bi_4.high, bi_6.high) > max(bi_4.low, bi_6.low) \
and (bi_3.high - bi_1.low) > (bi_9.high - bi_7.low): and (bi_3.high - bi_1.low) > (bi_9.high - bi_7.low):
v = ChanSignals.SA0.value return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2='九笔ABC式')
# 九笔三卖 # 类趋势类一卖
if bi_8.low > bi_6.high > bi_6.low > bi_4.high > bi_4.low > bi_2.high \
and bi_9.atan < max([bi_1.atan, bi_3.atan, bi_5.atan, bi_7.atan]):
return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2='九笔类趋势')
# aAbBc式类一卖
if max_high == bi_9.high and min_low == min(bi_1.low, bi_3.low) \
and bi_6.low > min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) \
and min(bi_6.high, bi_8.high) > max(bi_6.low, bi_8.low) \
and max(bi_2.high, bi_4.high) < min(bi_6.low, bi_8.low) \
and bi_9.height < bi_5.height and bi_9.atan <= bi_5.atan:
return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2='九笔aAbBc式')
# 九笔类三卖
if max_high == bi_1.high and min_low == bi_9.low \ if max_high == bi_1.high and min_low == bi_9.low \
and bi_9.high < max([x.low for x in [bi_3, bi_5, bi_7]]) < min([x.high for x in [bi_3, bi_5, bi_7]]): and bi_9.high < max([x.low for x in [bi_3, bi_5, bi_7]]) < min([x.high for x in [bi_3, bi_5, bi_7]]):
v = ChanSignals.SI0.value return ChanSignals.Q3S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类三卖', v2='九笔')
if min_low == bi_1.low and max_high == bi_5.high and bi_2.high < bi_4.low: # 前五笔构成向上类趋势
zd = max([x.low for x in [bi_5, bi_7]])
zg = min([x.high for x in [bi_5, bi_7]])
dd = min([x.low for x in [bi_5, bi_7]])
if zg > zd and bi_8.low < dd: # 567构成中枢且8的低点小于dd
if bi_9.high < zd:
return ChanSignals.Q3S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类三卖', v2='九笔ZD三卖')
# 类二卖
if dd < zd <= bi_9.high < zg:
return ChanSignals.Q2S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二卖', v2='九笔')
return v return v
def check_chan_xt_eleven_bi(kline: CtaLineBar, bi_list: List[ChanObject]): def check_chan_xt_eleven_bi(kline, bi_list: List[ChanObject]):
""" """
获取线段得背驰形态含11个分笔 获取线段得的类买卖点含11个分笔
:param cur_duan: :param cur_duan:
:return: :return:
""" """
@ -538,95 +677,126 @@ def check_chan_xt_eleven_bi(kline: CtaLineBar, bi_list: List[ChanObject]):
max_high = max([x.high for x in bi_list]) max_high = max([x.high for x in bi_list])
min_low = min([x.low for x in bi_list]) min_low = min([x.low for x in bi_list])
# 11笔向下寻找买点
if direction == -1: if direction == -1:
# 1笔最高11笔最低
if min_low == bi_11.low and max_high == bi_1.high: if min_low == bi_11.low and max_high == bi_1.high:
# aAbBc式底背驰bi_2-bi_6构成A
if min(bi_2.high, bi_4.high, bi_6.high) > max(bi_2.low, bi_4.low, bi_6.low) > bi_8.high \
and min(bi_8.high, bi_10.high) > max(bi_8.low, bi_10.low) \
and min(bi_2.low, bi_4.low, bi_6.low) > max(bi_8.high, bi_10.high) \
and bi_11.height < bi_7.height and bi_11.atan <= bi_7.atan:
v = ChanSignals.LA0.value
# aAbBc式底背驰bi_6-bi_10构成B # ABC式类一买A5B3C3
if min(bi_2.high, bi_4.high) > max(bi_2.low, bi_4.low) > bi_6.high \
and min(bi_6.high, bi_8.high, bi_10.high) > max(bi_6.low, bi_8.low, bi_10.low) \
and min(bi_2.low, bi_4.low) > max(bi_6.high, bi_8.high, bi_10.high) \
and bi_11.height < bi_5.height and bi_11.atan <= bi_5.atan:
v = ChanSignals.LA0.value
# ABC式底背驰A5B3C3
if bi_5.low == min([x.low for x in [bi_1, bi_3, bi_5]]) \ if bi_5.low == min([x.low for x in [bi_1, bi_3, bi_5]]) \
and bi_9.low > bi_11.low and bi_9.high > bi_11.high \ and bi_9.low > bi_11.low and bi_9.high > bi_11.high \
and bi_8.high > bi_6.low and bi_1.high - bi_5.low > bi_9.high - bi_11.low: and bi_8.high > bi_6.low and bi_1.high - bi_5.low > bi_9.high - bi_11.low:
v = ChanSignals.LA0.value return ChanSignals.Q1L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一买', v2="11笔A5B3C3式")
# C内部背驰
if bi_11.height < bi_9.height:
v = ChanSignals.LB0.value
# ABC式底背驰A3B3C5 # ABC式类一买A3B3C5
if bi_1.high > bi_3.high and bi_1.low > bi_3.low \ if bi_1.high > bi_3.high and bi_1.low > bi_3.low \
and bi_7.high == max([x.high for x in [bi_7, bi_9, bi_11]]) \ and bi_7.high == max([x.high for x in [bi_7, bi_9, bi_11]]) \
and bi_6.high > bi_4.low and bi_1.high - bi_3.low > bi_7.high - bi_11.low: and bi_6.high > bi_4.low and bi_1.high - bi_3.low > bi_7.high - bi_11.low:
v = ChanSignals.LA0.value return ChanSignals.Q1L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一买', v2="11笔A3B3C5式")
# C内部背驰
if bi_11.height < max(bi_9.height, bi_7.height) and bi_11.atan <= max(bi_9.atan, bi_7.atan):
v = ChanSignals.LB0.value
# ABC式底背驰A3B5C3 # ABC式类一买A3B5C3
if bi_1.low > bi_3.low and min(bi_4.high, bi_6.high, bi_8.high) > max(bi_4.low, bi_6.low, bi_8.low) \ if bi_1.low > bi_3.low and min(bi_4.high, bi_6.high, bi_8.high) > max(bi_4.low, bi_6.low, bi_8.low) \
and bi_9.high > bi_11.high and bi_1.high - bi_3.low > bi_9.high - bi_11.low: and bi_9.high > bi_11.high and bi_1.high - bi_3.low > bi_9.high - bi_11.low:
v = ChanSignals.LA0.value v = ChanSignals.Q1L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一买', v2="11笔A3B5C3式")
# C内部背驰
if bi_11.height < max(bi_9.height, bi_7.height) and bi_11.atan <= max(bi_9.atan, bi_7.atan):
v = ChanSignals.LB0.value
# a1Ab式类一买a11~7构成的类趋势
if bi_2.low > bi_4.high > bi_4.low > bi_6.high > bi_5.low > bi_7.low and bi_10.high > bi_8.low:
return ChanSignals.Q1L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一买', v2="11笔a1Ab式")
# 类二买1~9构成类趋势11不创新低,斜率低于9
if min_low == bi_9.low < bi_8.high < bi_6.low < bi_6.high < bi_4.low < bi_4.high < bi_2.low < bi_1.high == max_high \
and bi_11.low > bi_9.low and bi_9.atan > bi_11.atan:
return ChanSignals.Q2L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二买', v2="11笔")
# 类二买1~7构成盘整背驰246构成下跌中枢9/11构成上涨中枢且上涨中枢ZG大于下跌中枢ZG
if bi_7.atan < bi_1.atan and min_low == bi_7.low < max([x.low for x in [bi_2, bi_4, bi_6]]) \
< min([x.high for x in [bi_2, bi_4, bi_6]]) < max(
[x.high for x in [bi_9, bi_11]]) < bi_1.high == max_high \
and bi_11.low > min([x.low for x in [bi_2, bi_4, bi_6]]) \
and min([x.high for x in [bi_9, bi_11]]) > max([x.low for x in [bi_9, bi_11]]):
return ChanSignals.Q2L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二买', v2="11笔")
# 类二买1~7为区间极值9~11构成上涨中枢上涨中枢GG大于4~6的最大值上涨中枢DD大于4~6的最小值
if max_high == bi_1.high and min_low == bi_7.low \
and min(bi_9.high, bi_11.high) > max(bi_9.low, bi_11.low) \
and max(bi_11.high, bi_9.high) > max(bi_4.high, bi_6.high) \
and min(bi_9.low, bi_11.low) > min(bi_4.low, bi_6.low):
return ChanSignals.Q2L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二买', v2="11笔")
# 类三买1~9构成大级别中枢10离开11回调不跌破GG
gg = max([x.high for x in [bi_1, bi_2, bi_3]])
zg = min([x.high for x in [bi_1, bi_2, bi_3]])
zd = max([x.low for x in [bi_1, bi_2, bi_3]])
dd = min([x.low for x in [bi_1, bi_2, bi_3]])
if max_high == bi_11.high and bi_11.low > zg > zd \
and gg > bi_5.low and gg > bi_7.low and gg > bi_9.low \
and dd < bi_5.high and dd < bi_7.high and dd < bi_9.high:
return ChanSignals.Q3L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类三买', v2="11笔GG三买")
# 11笔向上寻找卖点
elif direction == 1: elif direction == 1:
# 1笔最低11笔最高
if max_high == bi_11.high and min_low == bi_1.low: if max_high == bi_11.high and min_low == bi_1.low:
# aAbBC式顶背驰bi_2-bi_6构成A
if bi_8.low > min(bi_2.high, bi_4.high, bi_6.high) >= max(bi_2.low, bi_4.low, bi_6.low) \
and min(bi_8.high, bi_10.high) >= max(bi_8.low, bi_10.low) \
and max(bi_2.high, bi_4.high, bi_6.high) < min(bi_8.low, bi_10.low) \
and bi_11.height < bi_7.height and bi_11.atan <= bi_7.atan:
v = ChanSignals.SA0.value
# aAbBC式顶背驰bi_6-bi_10构成B
if bi_6.low > min(bi_2.high, bi_4.high) >= max(bi_2.low, bi_4.low) \
and min(bi_6.high, bi_8.high, bi_10.high) >= max(bi_6.low, bi_8.low, bi_10.low) \
and max(bi_2.high, bi_4.high) < min(bi_6.low, bi_8.low, bi_10.low) \
and bi_11.height < bi_7.height and bi_11.atan <= bi_7.atan:
v = ChanSignals.SA0.value
# ABC式顶背驰A5B3C3 # ABC式顶背驰A5B3C3
if bi_5.high == max([bi_1.high, bi_3.high, bi_5.high]) and bi_9.low < bi_11.low and bi_9.high < bi_11.high \ if bi_5.high == max([bi_1.high, bi_3.high, bi_5.high]) and bi_9.low < bi_11.low and bi_9.high < bi_11.high \
and bi_8.low < bi_6.high and bi_11.high - bi_9.low < bi_5.high - bi_1.low: and bi_8.low < bi_6.high and bi_11.high - bi_9.low < bi_5.high - bi_1.low:
v = ChanSignals.SA0.value return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2="11笔A5B3C3式")
# C内部背驰
if bi_11.height < bi_9.height and bi_11.atan <= bi_9.atan:
v = ChanSignals.SB0.value
# ABC式顶背驰A3B3C5 # ABC式顶背驰A3B3C5
if bi_7.low == min([bi_11.low, bi_9.low, bi_7.low]) and bi_1.high < bi_3.high and bi_1.low < bi_3.low \ if bi_7.low == min([bi_11.low, bi_9.low, bi_7.low]) and bi_1.high < bi_3.high and bi_1.low < bi_3.low \
and bi_6.low < bi_4.high and bi_11.high - bi_7.low < bi_3.high - bi_1.low: and bi_6.low < bi_4.high and bi_11.high - bi_7.low < bi_3.high - bi_1.low:
v = ChanSignals.SA0.value return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2="11笔A3B3C5式")
# C内部背驰
if bi_11.height < max(bi_9.height, bi_7.height) and bi_11.atan <= max(bi_9.atan, bi_7.atan):
v = ChanSignals.SB0.value
# ABC式顶背驰A3B5C3 # ABC式顶背驰A3B5C3
if bi_1.high < bi_3.high and min(bi_4.high, bi_6.high, bi_8.high) > max(bi_4.low, bi_6.low, bi_8.low) \ if bi_1.high < bi_3.high and min(bi_4.high, bi_6.high, bi_8.high) > max(bi_4.low, bi_6.low, bi_8.low) \
and bi_9.low < bi_11.low and bi_3.high - bi_1.low > bi_11.high - bi_9.low: and bi_9.low < bi_11.low and bi_3.high - bi_1.low > bi_11.high - bi_9.low:
v = ChanSignals.SA0.value return ChanSignals.Q1S0.value
# C内部背驰
if bi_11.height < max(bi_9.height, bi_7.height) and bi_11.atan <= max(bi_9.atan, bi_7.atan): # a1Ab式类一卖a11~7构成的类趋势
v = ChanSignals.SB0.value if bi_2.high < bi_4.low < bi_4.high < bi_6.low < bi_5.high < bi_7.high and bi_10.low < bi_8.high:
return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2="11笔a1Ab式")
# 类二卖1~9构成类趋势11不创新高
if max_high == bi_9.high > bi_8.low > bi_6.high > bi_6.low > bi_4.high > bi_4.low > bi_2.high > bi_1.low == min_low \
and bi_11.high < bi_9.high and bi_9.atan > bi_11.atan:
return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二卖', v2="11笔")
# 类二卖1~7构成盘整背驰246构成上涨中枢9/11构成下跌中枢且下跌中枢DD小于上涨中枢ZD
if bi_7.atan < bi_1.atan and max_high == bi_7.high \
> min([x.high for x in [bi_2, bi_4, bi_6]]) \
> max([x.low for x in [bi_2, bi_4, bi_6]]) \
> min([x.low for x in [bi_9, bi_11]]) \
> bi_1.low == min_low \
and bi_11.high < max([x.high for x in [bi_2, bi_4, bi_6]]) \
and max([x.low for x in [bi_9, bi_11]]) < min([x.high for x in [bi_9, bi_11]]):
return ChanSignals.Q2S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二卖', v2="11笔")
# 类二卖1~7为区间极值9~11构成下跌中枢下跌中枢DD小于4~6的最小值下跌中枢GG小于4~6的最大值
if min_low == bi_1.low and max_high == bi_7.high \
and max(bi_9.low, bi_11.low) < min(bi_9.high, bi_11.high) \
and min(bi_11.low, bi_9.low) < min(bi_4.low, bi_6.low) \
and max(bi_9.high, bi_11.high) < max(bi_4.high, bi_6.high):
return ChanSignals.Q2S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类二卖', v2="11笔")
# 类三卖1~9构成大级别中枢10离开11回调不涨破DD
gg = min([x.low for x in [bi_1, bi_2, bi_3]])
zg = max([x.low for x in [bi_1, bi_2, bi_3]])
zd = min([x.high for x in [bi_1, bi_2, bi_3]])
dd = max([x.high for x in [bi_1, bi_2, bi_3]])
if min_low == bi_11.low and bi_11.high < zd < zg \
and dd < bi_5.high and dd < bi_7.high and dd < bi_9.high \
and gg > bi_5.low and gg > bi_7.low and gg > bi_9.low:
return ChanSignals.Q3S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类三卖', v2="11笔GG三买")
return v return v
def check_chan_xt_thirteen_bi(kline: CtaLineBar, bi_list: List[ChanObject]): def check_chan_xt_thirteen_bi(kline, bi_list: List[ChanObject]):
""" """
获取线段得背驰形态含13个分笔 获取线段得形态含13个分笔
:param cur_duan: :param kline:
:param bi_list: 由远及近的十三笔
:return: :return:
""" """
v = ChanSignals.Other.value v = ChanSignals.Other.value
@ -641,78 +811,48 @@ def check_chan_xt_thirteen_bi(kline: CtaLineBar, bi_list: List[ChanObject]):
# 下跌线段时,判断背驰类型 # 下跌线段时,判断背驰类型
if direction == -1: if direction == -1:
if min_low == bi_13.low and max_high == bi_1.high: if min_low == bi_13.low and max_high == bi_1.high:
# aAbBc式底背驰bi_2-bi_6构成Abi_8-bi_12构成B # ABC式类一买A5B3C5
if min(bi_2.high, bi_4.high, bi_6.high) > max(bi_2.low, bi_4.low, bi_6.low) > bi_8.high \
and min(bi_8.high, bi_10.high, bi_12.high) > max(bi_8.low, bi_10.low, bi_12.low) \
and min(bi_2.low, bi_4.low, bi_6.low) > max(bi_8.high, bi_10.high, bi_12.high) \
and bi_13.height < bi_7.height and bi_13.atan <= bi_7.atan:
v = ChanSignals.LA0.value
# ABC式底背驰A5B3C5
if bi_5.low < min(bi_1.low, bi_3.low) and bi_9.high > max(bi_11.high, bi_13.high) \ if bi_5.low < min(bi_1.low, bi_3.low) and bi_9.high > max(bi_11.high, bi_13.high) \
and bi_8.high > bi_6.low and bi_1.high - bi_5.low > bi_9.high - bi_13.low: and bi_8.high > bi_6.low and bi_1.high - bi_5.low > bi_9.high - bi_13.low:
v = ChanSignals.LA0.value return ChanSignals.Q1L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一买', v2="13笔A5B3C5式")
if bi_13.height < max(bi_11.height, bi_9.height) and bi_13.atan <= max(bi_11.atan, bi_9.atan): # ABC式类一买A3B5C5
v = ChanSignals.LB0.value
# ABC式底背驰A3B5C5
if bi_3.low < min(bi_1.low, bi_5.low) and bi_9.high > max(bi_11.high, bi_13.high) \ if bi_3.low < min(bi_1.low, bi_5.low) and bi_9.high > max(bi_11.high, bi_13.high) \
and min(bi_4.high, bi_6.high, bi_8.high) > max(bi_4.low, bi_6.low, bi_8.low) \ and min(bi_4.high, bi_6.high, bi_8.high) > max(bi_4.low, bi_6.low, bi_8.low) \
and bi_1.high - bi_3.low > bi_9.high - bi_13.low: and bi_1.high - bi_3.low > bi_9.high - bi_13.low:
v = ChanSignals.LA0.value return ChanSignals.Q1L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一买', v2="13笔A3B5C5式")
if bi_13.height < max(bi_11.height, bi_9.height) and bi_13.atan <= max(bi_11.atan, bi_9.atan):
v = ChanSignals.LB0.value
# ABC式底背驰A5B5C3 # ABC式底背驰A5B5C3
if bi_5.low < min(bi_1.low, bi_3.low) and bi_11.high > max(bi_9.high, bi_13.high) \ if bi_5.low < min(bi_1.low, bi_3.low) and bi_11.high > max(bi_9.high, bi_13.high) \
and min(bi_6.high, bi_8.high, bi_10.high) > max(bi_6.low, bi_8.low, bi_10.low) \ and min(bi_6.high, bi_8.high, bi_10.high) > max(bi_6.low, bi_8.low, bi_10.low) \
and bi_1.high - bi_5.low > bi_11.high - bi_13.low: and bi_1.high - bi_5.low > bi_11.high - bi_13.low:
v = ChanSignals.LA0.value return ChanSignals.Q1L0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一买', v2="13笔A5B5C3式")
if bi_13.height < bi_11.height and bi_13.atan <= bi_11.atan:
v = ChanSignals.LB0.value
# 上涨线段时,判断背驰类型 # 上涨线段时,判断背驰类型
elif direction == 1: elif direction == 1:
if max_high == bi_13.high and min_low == bi_1.low: if max_high == bi_13.high and min_low == bi_1.low:
# aAbBC式顶背驰bi_2-bi_6构成Abi_8-bi_12构成B
if bi_8.low > min(bi_2.high, bi_4.high, bi_6.high) >= max(bi_2.low, bi_4.low, bi_6.low) \
and min(bi_8.high, bi_10.high, bi_12.high) >= max(bi_8.low, bi_10.low, bi_12.low) \
and max(bi_2.high, bi_4.high, bi_6.high) < min(bi_8.low, bi_10.low, bi_12.low) \
and bi_13.height < bi_7.height and bi_13.atan <= bi_7.atan:
v = ChanSignals.SA0.value
# ABC式顶背驰A5B3C5 # ABC式顶背驰A5B3C5
if bi_5.high > max(bi_3.high, bi_1.high) and bi_9.low < min(bi_11.low, bi_13.low) \ if bi_5.high > max(bi_3.high, bi_1.high) and bi_9.low < min(bi_11.low, bi_13.low) \
and bi_8.low < bi_6.high and bi_5.high - bi_1.low > bi_13.high - bi_9.low: and bi_8.low < bi_6.high and bi_5.high - bi_1.low > bi_13.high - bi_9.low:
v = ChanSignals.SA0.value return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2="13笔A5B3C5式")
# C内部顶背驰形成双重顶背驰
if bi_13.height < max(bi_11.height, bi_9.height) and bi_13.atan <= max(bi_11.atan, bi_9.atan):
v = ChanSignals.SB0.value
# ABC式顶背驰A3B5C5 # ABC式顶背驰A3B5C5
if bi_3.high > max(bi_5.high, bi_1.high) and bi_9.low < min(bi_11.low, bi_13.low) \ if bi_3.high > max(bi_5.high, bi_1.high) and bi_9.low < min(bi_11.low, bi_13.low) \
and min(bi_4.high, bi_6.high, bi_8.high) > max(bi_4.low, bi_6.low, bi_8.low) \ and min(bi_4.high, bi_6.high, bi_8.high) > max(bi_4.low, bi_6.low, bi_8.low) \
and bi_3.high - bi_1.low > bi_13.high - bi_9.low: and bi_3.high - bi_1.low > bi_13.high - bi_9.low:
v = ChanSignals.SA0.value return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2="13笔A3B5C5式")
# C内部顶背驰形成双重顶背驰
if bi_13.height < max(bi_11.height, bi_9.height) and bi_13.atan <= max(bi_11.atan, bi_9.atan):
v = ChanSignals.SB0.value
# ABC式顶背驰A5B5C3 # ABC式顶背驰A5B5C3
if bi_5.high > max(bi_3.high, bi_1.high) and bi_11.low < min(bi_9.low, bi_13.low) \ if bi_5.high > max(bi_3.high, bi_1.high) and bi_11.low < min(bi_9.low, bi_13.low) \
and min(bi_6.high, bi_8.high, bi_10.high) > max(bi_6.low, bi_8.low, bi_10.low) \ and min(bi_6.high, bi_8.high, bi_10.high) > max(bi_6.low, bi_8.low, bi_10.low) \
and bi_5.high - bi_1.low > bi_13.high - bi_11.low: and bi_5.high - bi_1.low > bi_13.high - bi_11.low:
v = ChanSignals.SA0.value return ChanSignals.Q1S0.value # Signal(k1=freq.value, k2=di_name, k3='类买卖点', v1='类一卖', v2="13笔A5B5C3式")
# C内部顶背驰形成双重顶背驰
if bi_13.height < bi_11.height and bi_13.atan <= bi_11.atan:
v = ChanSignals.SB0.value
return v return v
def check_pzbc_1st(big_kline: CtaLineBar, small_kline: Union[CtaLineBar, None], signal_direction: Direction): # def check_pzbc_1st(big_kline, small_kline: Union[CtaLineBar, None], signal_direction: Direction):
def check_pzbc_1st(big_kline, small_kline, signal_direction: Direction):
""" """
判断中枢盘整背驰1买/1卖信号 判断中枢盘整背驰1买/1卖信号
big_kline当前线段为调整段与信号方向相反线段具有盘整一个中枢 big_kline当前线段为调整段与信号方向相反线段具有盘整一个中枢
@ -806,7 +946,8 @@ def check_pzbc_1st(big_kline: CtaLineBar, small_kline: Union[CtaLineBar, None],
return False return False
def check_qsbc_1st(big_kline: CtaLineBar, small_kline: Union[CtaLineBar, None], signal_direction: Direction): # def check_qsbc_1st(big_kline, small_kline: Union[CtaLineBar, None], signal_direction: Direction):
def check_qsbc_1st(big_kline, small_kline, signal_direction: Direction):
""" """
判断趋势背驰1买/1卖信号 判断趋势背驰1买/1卖信号
big_kline当前线段为趋势与信号方向相反线段具有2个中枢 big_kline当前线段为趋势与信号方向相反线段具有2个中枢
@ -890,7 +1031,8 @@ def check_qsbc_1st(big_kline: CtaLineBar, small_kline: Union[CtaLineBar, None],
return False return False
def check_pz3bc_1st(big_kline: CtaLineBar, small_kline: Union[CtaLineBar, None], signal_direction: Direction): # def check_pz3bc_1st(big_kline, small_kline: Union[CtaLineBar, None], signal_direction: Direction):
def check_pz3bc_1st(big_kline, small_kline, signal_direction: Direction):
""" """
判断三卖后盘整背驰一买/三买后盘整背驰1卖信号 判断三卖后盘整背驰一买/三买后盘整背驰1卖信号
big_kline当前线段与信号方向相反线段具有盘整一个中枢离开中枢的一笔力度与三买/卖信号后的一笔对比高度斜率 big_kline当前线段与信号方向相反线段具有盘整一个中枢离开中枢的一笔力度与三买/卖信号后的一笔对比高度斜率
@ -966,7 +1108,8 @@ def check_pz3bc_1st(big_kline: CtaLineBar, small_kline: Union[CtaLineBar, None],
return False return False
def check_qjt_1st(big_kline: CtaLineBar, small_kline: Union[CtaLineBar, None], signal_direction: Direction): # def check_qjt_1st(big_kline, small_kline: Union[CtaLineBar, None], signal_direction: Direction):
def check_qjt_1st(big_kline, small_kline, signal_direction: Direction):
""" """
判断区间套一买/区间套1卖信号 判断区间套一买/区间套1卖信号
big_kline当前线段与信号方向相反线段具有盘整一个中枢 big_kline当前线段与信号方向相反线段具有盘整一个中枢
@ -1038,7 +1181,8 @@ def check_qjt_1st(big_kline: CtaLineBar, small_kline: Union[CtaLineBar, None], s
return False return False
def check_qsbc_2nd(big_kline: CtaLineBar, small_kline: Union[CtaLineBar, None], signal_direction: Direction): # def check_qsbc_2nd(big_kline, small_kline: Union[CtaLineBar, None], signal_direction: Direction):
def check_qsbc_2nd(big_kline, small_kline, signal_direction: Direction):
""" """
判断趋势背驰1买/1卖后的二买二卖信号 判断趋势背驰1买/1卖后的二买二卖信号
big_kline当前线段为趋势与信号方向相反线段具有2个中枢 big_kline当前线段为趋势与信号方向相反线段具有2个中枢
@ -1136,8 +1280,9 @@ def check_qsbc_2nd(big_kline: CtaLineBar, small_kline: Union[CtaLineBar, None],
return True return True
def check_zs_3rd(big_kline: CtaLineBar, # : Union[CtaLineBar, None]
small_kline: Union[CtaLineBar, None], def check_zs_3rd(big_kline,
small_kline,
signal_direction: Direction, signal_direction: Direction,
first_zs: bool = True, first_zs: bool = True,
all_zs: bool = True): all_zs: bool = True):
@ -1181,7 +1326,7 @@ def check_zs_3rd(big_kline: CtaLineBar,
zs_list = [zs for zs in big_kline.bi_zs_list[-3:] if zs.start >= big_kline.cur_duan.start] zs_list = [zs for zs in big_kline.bi_zs_list[-3:] if zs.start >= big_kline.cur_duan.start]
zs_num = len(zs_list) zs_num = len(zs_list)
# 是否现在线段得首个中枢后的三买三卖 # 是否现在线段得首个中枢后的三买三卖
if first_zs and zs_num> 1: if first_zs and zs_num > 1:
return False return False
else: else:
# 中枢需要与当前线段有交集[部分交集、或中枢完全在当前段内形成] # 中枢需要与当前线段有交集[部分交集、或中枢完全在当前段内形成]

View File

@ -112,7 +112,7 @@ def download_adjust_factor():
login_msg = bs.login() login_msg = bs.login()
if login_msg.error_code != '0': if login_msg.error_code != '0':
print(f'证券宝登录错误代码:{login_msg.error_code}, 错误信息:{login_msg.error_msg}') print(f'证券宝登录错误代码:{login_msg.error_code}, 错误信息:{login_msg.error_msg}')
return return None
for k, v in base_dict.items(): for k, v in base_dict.items():
if v.get('类型') != '股票': if v.get('类型') != '股票':
@ -127,6 +127,7 @@ def download_adjust_factor():
save_data_to_pkb2(factor_dict, cache_file_name) save_data_to_pkb2(factor_dict, cache_file_name)
print(f'保存除权除息至文件:{cache_file_name}') print(f'保存除权除息至文件:{cache_file_name}')
return factor_dict
if __name__ == '__main__': if __name__ == '__main__':
download_adjust_factor() download_adjust_factor()

View File

@ -415,7 +415,7 @@ class PbGateway(BaseGateway):
def process_timer_event(self, event) -> None: def process_timer_event(self, event) -> None:
"""""" """"""
self.count += 1 self.count += 1
if self.count < 2: if self.count < 5:
return return
self.count = 0 self.count = 0
@ -1116,10 +1116,26 @@ class PbTdApi(object):
'{}{}.dbf'.format( '{}{}.dbf'.format(
PB_FILE_NAMES.get('accounts'), PB_FILE_NAMES.get('accounts'),
self.trading_date))) self.trading_date)))
copy_dbf = os.path.abspath(os.path.join(self.account_folder,
'{}{}_{}.dbf'.format(
PB_FILE_NAMES.get('accounts'),
self.trading_date,
datetime.now().strftime('%H%M'))))
try: try:
if not os.path.exists(account_dbf):
return
if os.path.exists(copy_dbf):
os.remove(copy_dbf)
# =》转移至于新文件
os.rename(account_dbf, copy_dbf)
if not os.path.exists(copy_dbf):
return
# dbf => 资金帐号信息 # dbf => 资金帐号信息
self.gateway.write_log(f'扫描资金帐号信息:{account_dbf}') self.gateway.write_log(f'扫描资金帐号信息:{copy_dbf}')
table = dbf.Table(account_dbf, codepage='cp936') table = dbf.Table(copy_dbf, codepage='cp936')
table.open(dbf.READ_ONLY) table.open(dbf.READ_ONLY)
for data in table: for data in table:
# ["资金账户"] # ["资金账户"]
@ -1137,6 +1153,8 @@ class PbTdApi(object):
table.close() table.close()
self.warning_dict.pop('query_account', None) self.warning_dict.pop('query_account', None)
if os.path.exists(copy_dbf):
os.remove(copy_dbf)
except Exception as ex: except Exception as ex:
err_msg = f'dbf扫描资金帐号异常:{str(ex)}' err_msg = f'dbf扫描资金帐号异常:{str(ex)}'
@ -1200,10 +1218,24 @@ class PbTdApi(object):
'{}{}.dbf'.format( '{}{}.dbf'.format(
PB_FILE_NAMES.get('positions'), PB_FILE_NAMES.get('positions'),
self.trading_date))) self.trading_date)))
copy_dbf = os.path.abspath(os.path.join(self.account_folder,
'{}{}_{}.dbf'.format(
PB_FILE_NAMES.get('positions'),
self.trading_date,
datetime.now().strftime('%H%M'))))
try: try:
if not os.path.exists(position_dbf):
return
if os.path.exists(copy_dbf):
os.remove(copy_dbf)
os.rename(position_dbf, copy_dbf)
if not os.path.exists(copy_dbf):
return
# dbf => 股票持仓信息 # dbf => 股票持仓信息
self.gateway.write_log(f'扫描股票持仓信息:{position_dbf}') self.gateway.write_log(f'扫描股票持仓信息:{copy_dbf}')
table = dbf.Table(position_dbf, codepage='cp936') table = dbf.Table(copy_dbf, codepage='cp936')
table.open(dbf.READ_ONLY) table.open(dbf.READ_ONLY)
for data in table: for data in table:
if str(data.zjzh).strip() != self.userid: if str(data.zjzh).strip() != self.userid:
@ -1242,6 +1274,9 @@ class PbTdApi(object):
table.close() table.close()
self.warning_dict.pop('query_position', None) self.warning_dict.pop('query_position', None)
if os.path.exists(copy_dbf):
os.remove(copy_dbf)
except Exception as ex: except Exception as ex:
err_msg = f'dbf扫描股票持仓异常:{str(ex)}' err_msg = f'dbf扫描股票持仓异常:{str(ex)}'
@ -1325,6 +1360,8 @@ class PbTdApi(object):
PB_FILE_NAMES.get('orders'), PB_FILE_NAMES.get('orders'),
self.trading_date))) self.trading_date)))
try: try:
if not os.path.exists(orders_dbf):
return
# dbf => 股票委托信息 # dbf => 股票委托信息
self.gateway.write_log(f'扫描股票委托信息:{orders_dbf}') self.gateway.write_log(f'扫描股票委托信息:{orders_dbf}')
table = dbf.Table(orders_dbf, codepage='cp936') table = dbf.Table(orders_dbf, codepage='cp936')
@ -1506,8 +1543,9 @@ class PbTdApi(object):
'{}{}.dbf'.format( '{}{}.dbf'.format(
PB_FILE_NAMES.get('update_orders'), PB_FILE_NAMES.get('update_orders'),
self.trading_date))) self.trading_date)))
# dbf => 所有委托记录
try: try:
if not os.path.exists(orders_dbf):
return
# dbf => 所有成交记录 # dbf => 所有成交记录
self.gateway.write_log(f'扫描所有委托查询:{orders_dbf}') self.gateway.write_log(f'扫描所有委托查询:{orders_dbf}')
table = dbf.Table(orders_dbf, codepage='cp936') table = dbf.Table(orders_dbf, codepage='cp936')
@ -1686,6 +1724,8 @@ class PbTdApi(object):
PB_FILE_NAMES.get('trades'), PB_FILE_NAMES.get('trades'),
self.trading_date))) self.trading_date)))
try: try:
if not os.path.exists(trades_dbf):
return
# dbf => 股票成交信息 # dbf => 股票成交信息
self.gateway.write_log(f'扫描股票成交信息:{trades_dbf}') self.gateway.write_log(f'扫描股票成交信息:{trades_dbf}')
table = dbf.Table(trades_dbf, codepage='cp936') table = dbf.Table(trades_dbf, codepage='cp936')
@ -1824,6 +1864,8 @@ class PbTdApi(object):
self.trading_date))) self.trading_date)))
try: try:
if not os.path.exists(trades_dbf):
return
# dbf => 所有成交记录 # dbf => 所有成交记录
self.gateway.write_log(f'扫描所有成交记录:{trades_dbf}') self.gateway.write_log(f'扫描所有成交记录:{trades_dbf}')
table = dbf.Table(trades_dbf, codepage='cp936') table = dbf.Table(trades_dbf, codepage='cp936')
@ -1981,6 +2023,9 @@ class PbTdApi(object):
dbf_file = os.path.abspath(os.path.join(self.order_folder, dbf_file = os.path.abspath(os.path.join(self.order_folder,
'{}{}.dbf'.format(PB_FILE_NAMES.get('send_order'), self.trading_date))) '{}{}.dbf'.format(PB_FILE_NAMES.get('send_order'), self.trading_date)))
try: try:
if not os.path.exists(dbf_file):
return
table = dbf.Table(dbf_file, codepage='cp936') table = dbf.Table(dbf_file, codepage='cp936')
table.open(dbf.READ_ONLY) table.open(dbf.READ_ONLY)
for record in table: for record in table:

View File

@ -214,85 +214,20 @@ class ChanSignals(Enum):
LB0 = "LB0~双重底背驰" LB0 = "LB0~双重底背驰"
LG0 = "LG0~上颈线突破" LG0 = "LG0~上颈线突破"
LH0 = "LH0~向上中枢完成" LH0 = "LH0~向上中枢完成"
LI0 = "LI0~三买" LI0 = "LI0~三买"
LJ0 = "LJ0~向上三角扩张中枢" LJ0 = "LJ0~向上三角扩张中枢"
LK0 = "LK0~向上三角收敛中枢" LK0 = "LK0~向上三角收敛中枢"
LL0 = "LL0~向上平台型中枢" LL0 = "LL0~向上平台型中枢"
# ------------------------------------------------------------------------------------------------------------------
LA1 = "LA1~底背驰特例一"
LA2 = "LA2~底背驰特例二"
LA3 = "LA3~底背驰特例三"
LB1 = "LB1~双重底背驰特例一"
LB2 = "LB2~双重底背驰特例二"
LB3 = "LB3~双重底背驰特例三"
LG1 = "LG1~上颈线突破特例一"
LG2 = "LG2~上颈线突破特例二"
LG3 = "LG3~上颈线突破特例三"
LH1 = "LH1~向上中枢完成特例一"
LH2 = "LH2~向上中枢完成特例二"
LH3 = "LH3~向上中枢完成特例三"
LI1 = "LI1~三买特例一"
LI2 = "LI2~三买特例二"
LI3 = "LI3~三买特例三"
LJ1 = "LJ1~向上三角扩张中枢特例一"
LJ2 = "LJ2~向上三角扩张中枢特例二"
LJ3 = "LJ3~向上三角扩张中枢特例三"
LK1 = "LK1~向上三角收敛中枢特例一"
LK2 = "LK2~向上三角收敛中枢特例二"
LK3 = "LK3~向上三角收敛中枢特例三"
LL1 = "LL1~向上平台型中枢特例一"
LL2 = "LL2~向上平台型中枢特例二"
LL3 = "LL3~向上平台型中枢特例三"
# ------------------------------------------------------------------------------------------------------------------ # ------------------------------------------------------------------------------------------------------------------
SA0 = "SA0~顶背驰" SA0 = "SA0~顶背驰"
SB0 = "SB0~双重顶背驰" SB0 = "SB0~双重顶背驰"
SG0 = "SG0~下颈线突破" SG0 = "SG0~下颈线突破"
SH0 = "SH0~向下中枢完成" SH0 = "SH0~向下中枢完成"
SI0 = "SI0~三卖" SI0 = "SI0~类三卖"
SJ0 = "SJ0~向下三角扩张中枢" SJ0 = "SJ0~向下三角扩张中枢"
SK0 = "SK0~向下三角收敛中枢" SK0 = "SK0~向下三角收敛中枢"
SL0 = "SL0~向下平台型中枢" SL0 = "SL0~向下平台型中枢"
# ------------------------------------------------------------------------------------------------------------------
SA1 = "SA1~顶背驰特例一"
SA2 = "SA2~顶背驰特例二"
SA3 = "SA3~顶背驰特例三"
SB1 = "SB1~双重顶背驰特例一"
SB2 = "SB2~双重顶背驰特例二"
SB3 = "SB3~双重顶背驰特例三"
SG1 = "SG1~下颈线突破特例一"
SG2 = "SG2~下颈线突破特例二"
SG3 = "SG3~下颈线突破特例三"
SH1 = "SH1~向下中枢完成特例一"
SH2 = "SH2~向下中枢完成特例二"
SH3 = "SH3~向下中枢完成特例三"
SI1 = "SI1~三卖特例一"
SI2 = "SI2~三卖特例二"
SI3 = "SI3~三卖特例三"
SJ1 = "SJ1~向下三角扩张中枢特例一"
SJ2 = "SJ2~向下三角扩张中枢特例二"
SJ3 = "SJ3~向下三角扩张中枢特例三"
SK1 = "SK1~向下三角收敛中枢特例一"
SK2 = "SK2~向下三角收敛中枢特例二"
SK3 = "SK3~向下三角收敛中枢特例三"
SL1 = "SL1~向下平台型中枢特例一"
SL2 = "SL2~向下平台型中枢特例二"
SL3 = "SL3~向下平台型中枢特例三"
# -------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------
# 信号值编码规则: # 信号值编码规则:
@ -304,16 +239,24 @@ class ChanSignals(Enum):
# 三笔形态信号 # 三笔形态信号
# -------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------
X3LA0 = "X3LA0~向下不重合" X3LA0 = "X3LA0~向下不重合"
X3LB0 = "X3LB0~向下奔走型中枢" X3LB0 = "X3LB0~向下奔走型"
X3LC0 = "X3LC0~向下三角收敛中枢" X3LC0 = "X3LC0~向下收敛"
X3LD0 = "X3LD0~向下三角扩张中枢" X3LD0 = "X3LD0~向下扩张"
X3LE0 = "X3LE0~向下盘背中枢" X3LE0 = "X3LE0~向下盘背"
X3LF0 = "X3LF0~向下无背中枢" X3LF0 = "X3LF0~向下无背"
X3SA0 = "X3SA0~向上不重合" X3SA0 = "X3SA0~向上不重合"
X3SB0 = "X3SB0~向上奔走型中枢" X3SB0 = "X3SB0~向上奔走型"
X3SC0 = "X3SC0~向上三角收敛中枢" X3SC0 = "X3SC0~向上收敛"
X3SD0 = "X3SD0~向上三角扩张中枢" X3SD0 = "X3SD0~向上扩张"
X3SE0 = "X3SE0~向上盘背中枢" X3SE0 = "X3SE0~向上盘背"
X3SF0 = "X3SF0~向上无背中枢" X3SF0 = "X3SF0~向上无背"
# 趋势类买卖点
Q1L0 = "Q1L0~趋势类一买"
Q2L0 = "Q2L0~趋势类二买"
Q3L0 = "Q2L0~趋势类三买"
Q1S0 = "Q1S0~趋势类一卖"
Q2S0 = "Q2S0~趋势类二卖"
Q3S0 = "Q2S0~趋势类三卖"

View File

@ -171,6 +171,8 @@ class MainEngine:
gateway = self.get_gateway(gateway_name) gateway = self.get_gateway(gateway_name)
if gateway: if gateway:
return gateway.get_default_setting() return gateway.get_default_setting()
else:
self.write_error(f'获取网格设置时,找不到{gateway_name}')
return None return None
def get_all_gateway_names(self) -> List[str]: def get_all_gateway_names(self) -> List[str]:
@ -209,6 +211,8 @@ class MainEngine:
except Exception as ex: except Exception as ex:
msg = f'gateway:{gateway_name}启动连接失败:{str(ex)}' msg = f'gateway:{gateway_name}启动连接失败:{str(ex)}'
self.write_log(msg=msg) self.write_log(msg=msg)
else:
self.write_error(f'连接{gateway_name}时,系统找不到{gateway_name}')
def subscribe(self, req: SubscribeRequest, gateway_name: str) -> None: def subscribe(self, req: SubscribeRequest, gateway_name: str) -> None:
""" """
@ -219,6 +223,8 @@ class MainEngine:
gateway = self.get_gateway(gateway_name) gateway = self.get_gateway(gateway_name)
if gateway: if gateway:
gateway.subscribe(req) gateway.subscribe(req)
else:
self.write_error(f'订阅合约时,找不到{gateway_name}')
else: else:
for gateway in self.gateways.values(): for gateway in self.gateways.values():
if gateway: if gateway:
@ -239,6 +245,7 @@ class MainEngine:
if gateway: if gateway:
return gateway.send_order(req) return gateway.send_order(req)
else: else:
self.write_error(f'发送委托时,找不到{gateway_name}')
return "" return ""
def cancel_order(self, req: CancelRequest, gateway_name: str) -> bool: def cancel_order(self, req: CancelRequest, gateway_name: str) -> bool:
@ -253,6 +260,8 @@ class MainEngine:
gateway = self.get_gateway(gateway_name) gateway = self.get_gateway(gateway_name)
if gateway: if gateway:
return gateway.cancel_order(req) return gateway.cancel_order(req)
else:
self.write_error(f'撤单时,找不到{gateway_name}')
return False return False
def send_orders(self, reqs: Sequence[OrderRequest], gateway_name: str) -> List[str]: def send_orders(self, reqs: Sequence[OrderRequest], gateway_name: str) -> List[str]:
@ -263,6 +272,7 @@ class MainEngine:
if gateway: if gateway:
return gateway.send_orders(reqs) return gateway.send_orders(reqs)
else: else:
self.write_error(f'批量发单时,找不到{gateway_name}')
return ["" for req in reqs] return ["" for req in reqs]
def cancel_orders(self, reqs: Sequence[CancelRequest], gateway_name: str) -> None: def cancel_orders(self, reqs: Sequence[CancelRequest], gateway_name: str) -> None:
@ -271,6 +281,8 @@ class MainEngine:
gateway = self.get_gateway(gateway_name) gateway = self.get_gateway(gateway_name)
if gateway: if gateway:
gateway.cancel_orders(reqs) gateway.cancel_orders(reqs)
else:
self.write_error(f'批量撤单时,找不到{gateway_name}')
def query_history(self, req: HistoryRequest, gateway_name: str) -> Optional[List[BarData]]: def query_history(self, req: HistoryRequest, gateway_name: str) -> Optional[List[BarData]]:
""" """
@ -280,7 +292,7 @@ class MainEngine:
if gateway: if gateway:
return gateway.query_history(req) return gateway.query_history(req)
else: else:
self.write_error(f'网关为空,请检查合约得网关是否与连接得网关一致') self.write_error(f'找不到网关{gateway_name},请检查合约得网关是否与连接得网关一致')
return None return None
def close(self) -> None: def close(self) -> None:

View File

@ -135,6 +135,7 @@ class OrderData(BaseData):
symbol: str symbol: str
exchange: Exchange exchange: Exchange
orderid: str orderid: str
name: str = ""
sys_orderid: str = "" sys_orderid: str = ""
accountid: str = "" accountid: str = ""
type: OrderType = OrderType.LIMIT type: OrderType = OrderType.LIMIT
@ -153,6 +154,8 @@ class OrderData(BaseData):
self.vt_symbol = f"{self.symbol}.{self.exchange.value}" self.vt_symbol = f"{self.symbol}.{self.exchange.value}"
self.vt_orderid = f"{self.gateway_name}.{self.orderid}" self.vt_orderid = f"{self.gateway_name}.{self.orderid}"
self.vt_accountid = f"{self.gateway_name}.{self.accountid}" self.vt_accountid = f"{self.gateway_name}.{self.accountid}"
if len(self.name) == 0:
self.name = self.vt_symbol
def is_active(self) -> bool: def is_active(self) -> bool:
""" """
@ -184,6 +187,7 @@ class TradeData(BaseData):
exchange: Exchange exchange: Exchange
orderid: str orderid: str
tradeid: str tradeid: str
name: str = ""
sys_orderid: str = "" sys_orderid: str = ""
accountid: str = "" accountid: str = ""
@ -208,7 +212,8 @@ class TradeData(BaseData):
self.vt_orderid = f"{self.gateway_name}.{self.orderid}" self.vt_orderid = f"{self.gateway_name}.{self.orderid}"
self.vt_tradeid = f"{self.gateway_name}.{self.tradeid}" self.vt_tradeid = f"{self.gateway_name}.{self.tradeid}"
self.vt_accountid = f"{self.gateway_name}.{self.accountid}" self.vt_accountid = f"{self.gateway_name}.{self.accountid}"
if len(self.name) == 0:
self.name = self.vt_symbol
@dataclass @dataclass
class PositionData(BaseData): class PositionData(BaseData):

View File

@ -347,6 +347,9 @@ def get_csv_last_dt(file_name, dt_index=0, dt_format='%Y-%m-%d %H:%M:%S', line_l
:param line_length: 行数据的长度 :param line_length: 行数据的长度
:return: None文件不存在或者时间格式不正确 :return: None文件不存在或者时间格式不正确
""" """
if not os.path.exists(file_name):
return False
with open(file_name, 'r') as f: with open(file_name, 'r') as f:
f_size = os.path.getsize(file_name) f_size = os.path.getsize(file_name)
if f_size < line_length: if f_size < line_length:
@ -1442,3 +1445,4 @@ def get_remote_file(remote_ip, remote_file_path, mode='rb'):
except Exception as ex: except Exception as ex:
print(u'打开远程目录异常:{}'.format(str(ex))) print(u'打开远程目录异常:{}'.format(str(ex)))
return None return None