[增强] 期货CtaPro模板, 组合回测引擎(支持tick级别组合回测)
This commit is contained in:
parent
c5f71910d5
commit
ee2fd126f4
@ -37,8 +37,11 @@
|
|||||||
- 提供单独重启某一策略实例功能,可在线更新策略源码后,重启某一策略实例,不影响其他运行实例。
|
- 提供单独重启某一策略实例功能,可在线更新策略源码后,重启某一策略实例,不影响其他运行实例。
|
||||||
- 支持单策略多合约行情订阅,支持指数合约行情订阅
|
- 支持单策略多合约行情订阅,支持指数合约行情订阅
|
||||||
- 提供组合回测引擎,能够直接加载cta_strategy_pro_setting.json文件进行组合回测。
|
- 提供组合回测引擎,能够直接加载cta_strategy_pro_setting.json文件进行组合回测。
|
||||||
|
- 拆分组合回测引擎和回测引擎,组合回测引擎支持bar/tick级别的组合回测
|
||||||
- 增加定时器,推动策略on_timer
|
- 增加定时器,推动策略on_timer
|
||||||
- 增加定时推送策略持仓event
|
- 增加定时推送策略持仓event
|
||||||
|
- 增加CtaPro模板,支持精细化策略持久模板,
|
||||||
|
- 增加CtaPro期货模板,支持FAK委托,自动换月等
|
||||||
|
|
||||||
8、增强主引擎,包括:
|
8、增强主引擎,包括:
|
||||||
|
|
||||||
|
@ -5,8 +5,6 @@ qdarkstyle
|
|||||||
requests
|
requests
|
||||||
websocket-client
|
websocket-client
|
||||||
peewee
|
peewee
|
||||||
pymysql
|
|
||||||
psycopg2
|
|
||||||
mongoengine
|
mongoengine
|
||||||
numpy
|
numpy
|
||||||
pandas>=0.24.2
|
pandas>=0.24.2
|
||||||
@ -21,3 +19,5 @@ deap
|
|||||||
pyzmq
|
pyzmq
|
||||||
wmi
|
wmi
|
||||||
QScintilla
|
QScintilla
|
||||||
|
pytdx
|
||||||
|
pykalman
|
||||||
|
@ -12,7 +12,7 @@ from vnpy.data.renko.rebuild_future import *
|
|||||||
|
|
||||||
# Mongo数据库得地址,renko数据库名,tick文件缓存目录
|
# Mongo数据库得地址,renko数据库名,tick文件缓存目录
|
||||||
setting = {
|
setting = {
|
||||||
"host": "192.168.0.207",
|
"host": "127.0.0.1",
|
||||||
"db_name": FUTURE_RENKO_DB_NAME,
|
"db_name": FUTURE_RENKO_DB_NAME,
|
||||||
"cache_folder": os.path.join(vnpy_root, 'tick_data', 'tdx', 'future')
|
"cache_folder": os.path.join(vnpy_root, 'tick_data', 'tdx', 'future')
|
||||||
}
|
}
|
||||||
@ -20,8 +20,12 @@ builder = FutureRenkoRebuilder(setting)
|
|||||||
|
|
||||||
# 生成单个
|
# 生成单个
|
||||||
# builder.start(symbol='RB99',min_diff=1, height=10, start_date='2019-04-01', end_date='2019-09-10')
|
# builder.start(symbol='RB99',min_diff=1, height=10, start_date='2019-04-01', end_date='2019-09-10')
|
||||||
|
|
||||||
# 生成多个
|
# 生成多个
|
||||||
builder.start(symbol='J99', price_tick=0.5, height=[10], start_date='2016-01-01', end_date='2016-02-16')
|
#builder.start(symbol='J99', price_tick=0.5, height=[10, 'K3'], start_date='2016-01-01', end_date='2016-02-16')
|
||||||
|
|
||||||
|
# 在数据库最新renko基础上开始追加数据
|
||||||
|
builder.start(symbol='J99', price_tick=0.5, height=[10, 'K3', 'K5'], start_date='2016-01-01', refill=True)
|
||||||
|
|
||||||
# 导出csv
|
# 导出csv
|
||||||
# builder.export(symbol='RB99',height=10, start_date='2019-04-01', end_date='2019-09-10')
|
# builder.export(symbol='RB99',height=10, start_date='2019-04-01', end_date='2019-09-10')
|
@ -14,21 +14,31 @@
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import copy
|
import copy
|
||||||
import traceback
|
import traceback
|
||||||
import csv
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from time import time
|
from time import time
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
|
||||||
|
|
||||||
from vnpy.event import Event, EventEngine
|
from vnpy.event import Event, EventEngine
|
||||||
from vnpy.trader.event import *
|
from vnpy.trader.event import (
|
||||||
from vnpy.trader.constant import Direction
|
EVENT_TIMER,
|
||||||
|
EVENT_ACCOUNT,
|
||||||
|
EVENT_ORDER,
|
||||||
|
EVENT_TRADE,
|
||||||
|
EVENT_POSITION,
|
||||||
|
EVENT_HISTORY_TRADE,
|
||||||
|
EVENT_HISTORY_ORDER,
|
||||||
|
EVENT_FUNDS_FLOW,
|
||||||
|
EVENT_STRATEGY_POS,
|
||||||
|
EVENT_ERROR,
|
||||||
|
EVENT_WARNING,
|
||||||
|
EVENT_CRITICAL,
|
||||||
|
)
|
||||||
|
# from vnpy.trader.constant import Direction
|
||||||
from vnpy.trader.engine import BaseEngine, MainEngine
|
from vnpy.trader.engine import BaseEngine, MainEngine
|
||||||
from vnpy.trader.utility import get_trading_date, load_json, save_json
|
from vnpy.trader.utility import get_trading_date, load_json, save_json
|
||||||
from vnpy.data.mongo.mongo_data import MongoData
|
from vnpy.data.mongo.mongo_data import MongoData
|
||||||
@ -246,7 +256,7 @@ class AccountRecorder(BaseEngine):
|
|||||||
self.save_setting()
|
self.save_setting()
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.main_engine.writeError(u'更新数据日期异常:{}'.format(str(ex)))
|
self.main_engine.write_error(u'更新数据日期异常:{}'.format(str(ex)))
|
||||||
self.write_log(traceback.format_exc())
|
self.write_log(traceback.format_exc())
|
||||||
|
|
||||||
def get_begin_day(self, gw_name: str, data_type: str):
|
def get_begin_day(self, gw_name: str, data_type: str):
|
||||||
@ -393,7 +403,7 @@ class AccountRecorder(BaseEngine):
|
|||||||
price = self.main_engine.get_price(pos.vt_symbol)
|
price = self.main_engine.get_price(pos.vt_symbol)
|
||||||
if price:
|
if price:
|
||||||
data.update({'cur_price': price})
|
data.update({'cur_price': price})
|
||||||
except:
|
except: # noqa
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.update_data(db_name=ACCOUNT_DB_NAME, col_name=TODAY_POSITION_COL, fld=fld, data=data)
|
self.update_data(db_name=ACCOUNT_DB_NAME, col_name=TODAY_POSITION_COL, fld=fld, data=data)
|
||||||
@ -561,7 +571,7 @@ class AccountRecorder(BaseEngine):
|
|||||||
self.write_log(u'运行 {}.{} 更新 耗时:{}ms >200ms,数据:{}'
|
self.write_log(u'运行 {}.{} 更新 耗时:{}ms >200ms,数据:{}'
|
||||||
.format(db_name, col_name, execute_ms, d))
|
.format(db_name, col_name, execute_ms, d))
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex: # noqa
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
@ -4,7 +4,6 @@ import traceback
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from inspect import getfile
|
|
||||||
|
|
||||||
from vnpy.event import Event, EventEngine
|
from vnpy.event import Event, EventEngine
|
||||||
from vnpy.trader.engine import BaseEngine, MainEngine
|
from vnpy.trader.engine import BaseEngine, MainEngine
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from vnpy.trader.app import BaseApp
|
from vnpy.trader.app import BaseApp
|
||||||
from vnpy.trader.constant import Direction,Offset,Status
|
from vnpy.trader.constant import Direction,Offset,Status,Color
|
||||||
from vnpy.trader.object import TickData, BarData, TradeData, OrderData
|
from vnpy.trader.object import TickData, BarData, TradeData, OrderData
|
||||||
from vnpy.trader.utility import BarGenerator, ArrayManager
|
from vnpy.trader.utility import BarGenerator, ArrayManager
|
||||||
from .cta_position import CtaPosition
|
from .cta_position import CtaPosition
|
||||||
from .cta_line_bar import CtaLineBar, CtaMinuteBar, CtaHourBar, CtaDayBar, CtaWeekBar
|
from .cta_line_bar import CtaLineBar, CtaMinuteBar, CtaHourBar, CtaDayBar, CtaWeekBar
|
||||||
|
from .base import APP_NAME, StopOrder, CtaComponent
|
||||||
from .cta_policy import CtaPolicy
|
from .cta_policy import CtaPolicy
|
||||||
from .cta_grid_trade import CtaGrid, CtaGridTrade
|
from .cta_grid_trade import CtaGrid, CtaGridTrade
|
||||||
from .base import APP_NAME, StopOrder
|
|
||||||
from .engine import CtaEngine
|
from .engine import CtaEngine
|
||||||
|
|
||||||
from .template import CtaTemplate, CtaSignal, TargetPosTemplate, CtaProTemplate
|
from .template import CtaTemplate, CtaSignal, TargetPosTemplate, CtaProTemplate, CtaProFutureTemplate
|
||||||
|
|
||||||
class CtaStrategyProApp(BaseApp):
|
class CtaStrategyProApp(BaseApp):
|
||||||
""""""
|
""""""
|
||||||
|
2159
vnpy/app/cta_strategy_pro/back_testing.py
Normal file
2159
vnpy/app/cta_strategy_pro/back_testing.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Defines constants and objects used in CtaStrategyPro App.
|
Defines constants and objects used in CtaStrategyPro App.
|
||||||
"""
|
"""
|
||||||
|
import sys
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
@ -93,6 +94,7 @@ INTERVAL_DELTA_MAP = {
|
|||||||
Interval.DAILY: timedelta(days=1),
|
Interval.DAILY: timedelta(days=1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class CtaComponent(ABC):
|
class CtaComponent(ABC):
|
||||||
""" CTA策略基础组件"""
|
""" CTA策略基础组件"""
|
||||||
|
|
||||||
@ -103,7 +105,6 @@ class CtaComponent(ABC):
|
|||||||
"""
|
"""
|
||||||
self.strategy = strategy
|
self.strategy = strategy
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def write_log(self, content: str):
|
def write_log(self, content: str):
|
||||||
"""记录日志"""
|
"""记录日志"""
|
||||||
if self.strategy:
|
if self.strategy:
|
||||||
@ -111,11 +112,9 @@ class CtaComponent(ABC):
|
|||||||
else:
|
else:
|
||||||
print(content)
|
print(content)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def write_error(self, content: str, level: int = ERROR):
|
def write_error(self, content: str, level: int = ERROR):
|
||||||
"""记录错误日志"""
|
"""记录错误日志"""
|
||||||
if self.strategy:
|
if self.strategy:
|
||||||
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)
|
||||||
|
|
||||||
|
@ -9,8 +9,6 @@ import traceback
|
|||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from typing import List
|
|
||||||
from vnpy.trader.utility import get_folder_path
|
from vnpy.trader.utility import get_folder_path
|
||||||
from vnpy.app.cta_strategy_pro.base import Direction, CtaComponent
|
from vnpy.app.cta_strategy_pro.base import Direction, CtaComponent
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import sys
|
|||||||
import traceback
|
import traceback
|
||||||
import talib as ta
|
import talib as ta
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import csv
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
@ -27,7 +28,7 @@ from vnpy.app.cta_strategy_pro.base import (
|
|||||||
MARKET_ZJ)
|
MARKET_ZJ)
|
||||||
from vnpy.app.cta_strategy_pro.cta_period import CtaPeriod, Period
|
from vnpy.app.cta_strategy_pro.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, Exchange
|
from vnpy.trader.constant import Interval, Color
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
@ -1062,7 +1063,6 @@ class CtaLineBar(object):
|
|||||||
|
|
||||||
self.line_bar.append(self.cur_bar) # 推入到lineBar队列
|
self.line_bar.append(self.cur_bar) # 推入到lineBar队列
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def generate_bar(self, tick: TickData):
|
def generate_bar(self, tick: TickData):
|
||||||
"""生成 line Bar """
|
"""生成 line Bar """
|
||||||
|
|
||||||
@ -1184,7 +1184,6 @@ class CtaLineBar(object):
|
|||||||
if not endtick:
|
if not endtick:
|
||||||
self.last_tick = tick
|
self.last_tick = tick
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def __count_pre_high_low(self):
|
def __count_pre_high_low(self):
|
||||||
"""计算 K线的前周期最高和最低"""
|
"""计算 K线的前周期最高和最低"""
|
||||||
|
|
||||||
@ -1206,7 +1205,6 @@ class CtaLineBar(object):
|
|||||||
del self.line_pre_low[0]
|
del self.line_pre_low[0]
|
||||||
self.line_pre_low.append(preLow)
|
self.line_pre_low.append(preLow)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def __count_sar(self):
|
def __count_sar(self):
|
||||||
"""计算K线的SAR"""
|
"""计算K线的SAR"""
|
||||||
|
|
||||||
@ -1331,7 +1329,6 @@ class CtaLineBar(object):
|
|||||||
if len(self.line_sar) > self.max_hold_bars:
|
if len(self.line_sar) > self.max_hold_bars:
|
||||||
del self.line_sar[0]
|
del self.line_sar[0]
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def __count_ma(self):
|
def __count_ma(self):
|
||||||
"""计算K线的MA1 和MA2"""
|
"""计算K线的MA1 和MA2"""
|
||||||
|
|
||||||
@ -1486,7 +1483,8 @@ class CtaLineBar(object):
|
|||||||
if self.para_ma1_len > 0:
|
if self.para_ma1_len > 0:
|
||||||
count_len = min(self.bar_len, self.para_ma1_len)
|
count_len = min(self.bar_len, self.para_ma1_len)
|
||||||
if count_len > 0:
|
if count_len > 0:
|
||||||
close_ma_array = ta.MA(np.append(self.close_array[-count_len:], [self.line_bar[-1].close_price]), count_len)
|
close_ma_array = ta.MA(np.append(self.close_array[-count_len:], [self.line_bar[-1].close_price]),
|
||||||
|
count_len)
|
||||||
self._rt_ma1 = round(float(close_ma_array[-1]), self.round_n)
|
self._rt_ma1 = round(float(close_ma_array[-1]), self.round_n)
|
||||||
|
|
||||||
# 计算斜率
|
# 计算斜率
|
||||||
@ -1497,7 +1495,8 @@ class CtaLineBar(object):
|
|||||||
if self.para_ma2_len > 0:
|
if self.para_ma2_len > 0:
|
||||||
count_len = min(self.bar_len, self.para_ma2_len)
|
count_len = min(self.bar_len, self.para_ma2_len)
|
||||||
if count_len > 0:
|
if count_len > 0:
|
||||||
close_ma_array = ta.MA(np.append(self.close_array[-count_len:], [self.line_bar[-1].close_price]), count_len)
|
close_ma_array = ta.MA(np.append(self.close_array[-count_len:], [self.line_bar[-1].close_price]),
|
||||||
|
count_len)
|
||||||
self._rt_ma2 = round(float(close_ma_array[-1]), self.round_n)
|
self._rt_ma2 = round(float(close_ma_array[-1]), self.round_n)
|
||||||
|
|
||||||
# 计算斜率
|
# 计算斜率
|
||||||
@ -1508,7 +1507,8 @@ class CtaLineBar(object):
|
|||||||
if self.para_ma3_len > 0:
|
if self.para_ma3_len > 0:
|
||||||
count_len = min(self.bar_len, self.para_ma3_len)
|
count_len = min(self.bar_len, self.para_ma3_len)
|
||||||
if count_len > 0:
|
if count_len > 0:
|
||||||
close_ma_array = ta.MA(np.append(self.close_array[-count_len:], [self.line_bar[-1].close_price]), count_len)
|
close_ma_array = ta.MA(np.append(self.close_array[-count_len:], [self.line_bar[-1].close_price]),
|
||||||
|
count_len)
|
||||||
self._rt_ma3 = round(float(close_ma_array[-1]), self.round_n)
|
self._rt_ma3 = round(float(close_ma_array[-1]), self.round_n)
|
||||||
|
|
||||||
# 计算斜率
|
# 计算斜率
|
||||||
@ -1558,7 +1558,6 @@ class CtaLineBar(object):
|
|||||||
return self.line_ma3_atan[-1]
|
return self.line_ma3_atan[-1]
|
||||||
return self._rt_ma3_atan
|
return self._rt_ma3_atan
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def __count_ema(self):
|
def __count_ema(self):
|
||||||
"""计算K线的EMA1 和EMA2"""
|
"""计算K线的EMA1 和EMA2"""
|
||||||
|
|
||||||
@ -1613,7 +1612,6 @@ class CtaLineBar(object):
|
|||||||
del self.line_ema3[0]
|
del self.line_ema3[0]
|
||||||
self.line_ema3.append(barEma3)
|
self.line_ema3.append(barEma3)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def rt_count_ema(self):
|
def rt_count_ema(self):
|
||||||
"""计算K线的EMA1 和EMA2"""
|
"""计算K线的EMA1 和EMA2"""
|
||||||
|
|
||||||
@ -1844,7 +1842,7 @@ class CtaLineBar(object):
|
|||||||
|
|
||||||
if self.para_atr3_len > 0:
|
if self.para_atr3_len > 0:
|
||||||
count_len = min(self.bar_len, self.para_atr3_len)
|
count_len = min(self.bar_len, self.para_atr3_len)
|
||||||
cur_atr3 = ta.ATR(self.high_array[-count_len * 2 :], self.low_array[-count_len * 2:],
|
cur_atr3 = ta.ATR(self.high_array[-count_len * 2:], self.low_array[-count_len * 2:],
|
||||||
self.close_array[-count_len * 2:], count_len)
|
self.close_array[-count_len * 2:], count_len)
|
||||||
self.cur_atr3 = round(cur_atr3[-1], self.round_n)
|
self.cur_atr3 = round(cur_atr3[-1], self.round_n)
|
||||||
|
|
||||||
@ -1853,7 +1851,6 @@ class CtaLineBar(object):
|
|||||||
|
|
||||||
self.line_atr3.append(self.cur_atr3)
|
self.line_atr3.append(self.cur_atr3)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def __count_vol_ma(self):
|
def __count_vol_ma(self):
|
||||||
"""计算平均成交量"""
|
"""计算平均成交量"""
|
||||||
|
|
||||||
@ -1869,7 +1866,6 @@ class CtaLineBar(object):
|
|||||||
del self.line_vol_ma[0]
|
del self.line_vol_ma[0]
|
||||||
self.line_vol_ma.append(avgVol)
|
self.line_vol_ma.append(avgVol)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def __count_rsi(self):
|
def __count_rsi(self):
|
||||||
"""计算K线的RSI"""
|
"""计算K线的RSI"""
|
||||||
if self.para_rsi1_len <= 0 and self.para_rsi2_len <= 0:
|
if self.para_rsi1_len <= 0 and self.para_rsi2_len <= 0:
|
||||||
@ -3943,7 +3939,6 @@ class CtaLineBar(object):
|
|||||||
return self.line_bias3[-1]
|
return self.line_bias3[-1]
|
||||||
return self._rt_bias3
|
return self._rt_bias3
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def write_log(self, content):
|
def write_log(self, content):
|
||||||
"""记录CTA日志"""
|
"""记录CTA日志"""
|
||||||
self.strategy.write_log(u'[' + self.name + u']' + content)
|
self.strategy.write_log(u'[' + self.name + u']' + content)
|
||||||
@ -4586,7 +4581,6 @@ class CtaMinuteBar(CtaLineBar):
|
|||||||
# 实时计算
|
# 实时计算
|
||||||
self.rt_executed = False
|
self.rt_executed = False
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def generate_bar(self, tick):
|
def generate_bar(self, tick):
|
||||||
"""
|
"""
|
||||||
生成 line Bar
|
生成 line Bar
|
||||||
@ -4821,8 +4815,6 @@ class CtaHourBar(CtaLineBar):
|
|||||||
# 实时计算
|
# 实时计算
|
||||||
self.rt_executed = False
|
self.rt_executed = False
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
|
|
||||||
def generate_bar(self, tick):
|
def generate_bar(self, tick):
|
||||||
"""
|
"""
|
||||||
生成 line Bar
|
生成 line Bar
|
||||||
@ -5047,7 +5039,6 @@ class CtaDayBar(CtaLineBar):
|
|||||||
# 实时计算
|
# 实时计算
|
||||||
self.rt_executed = False
|
self.rt_executed = False
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def generate_bar(self, tick):
|
def generate_bar(self, tick):
|
||||||
"""
|
"""
|
||||||
生成 line Bar
|
生成 line Bar
|
||||||
@ -5280,7 +5271,6 @@ class CtaWeekBar(CtaLineBar):
|
|||||||
'%Y-%m-%d %H:%M:%S')
|
'%Y-%m-%d %H:%M:%S')
|
||||||
return friday_night_dt
|
return friday_night_dt
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
|
||||||
def generate_bar(self, tick):
|
def generate_bar(self, tick):
|
||||||
"""
|
"""
|
||||||
生成 line Bar
|
生成 line Bar
|
||||||
@ -5338,4 +5328,3 @@ class CtaWeekBar(CtaLineBar):
|
|||||||
self.rt_executed = False
|
self.rt_executed = False
|
||||||
|
|
||||||
self.last_tick = tick
|
self.last_tick = tick
|
||||||
|
|
||||||
|
@ -7,6 +7,11 @@ from collections import OrderedDict
|
|||||||
from vnpy.app.cta_strategy_pro.base import CtaComponent
|
from vnpy.app.cta_strategy_pro.base import CtaComponent
|
||||||
from vnpy.trader.utility import get_folder_path
|
from vnpy.trader.utility import get_folder_path
|
||||||
|
|
||||||
|
TNS_STATUS_OBSERVATE = 'observate'
|
||||||
|
TNS_STATUS_ORDERING = 'ordering'
|
||||||
|
TNS_STATUS_OPENED = 'opened'
|
||||||
|
TNS_STATUS_CLOSED = 'closed'
|
||||||
|
|
||||||
|
|
||||||
class CtaPolicy(CtaComponent):
|
class CtaPolicy(CtaComponent):
|
||||||
"""
|
"""
|
||||||
@ -18,7 +23,7 @@ class CtaPolicy(CtaComponent):
|
|||||||
构造
|
构造
|
||||||
:param strategy:
|
:param strategy:
|
||||||
"""
|
"""
|
||||||
super(CtaPolicy,self).__init__(strategy=strategy, kwargs=kwargs)
|
super().__init__(strategy=strategy, kwargs=kwargs)
|
||||||
|
|
||||||
self.create_time = None
|
self.create_time = None
|
||||||
self.save_time = None
|
self.save_time = None
|
||||||
@ -67,7 +72,8 @@ class CtaPolicy(CtaComponent):
|
|||||||
从持久化文件中获取
|
从持久化文件中获取
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
json_file = os.path.abspath(os.path.join(get_folder_path('data'), u'{}_Policy.json'.format(self.strategy.strategy_name)))
|
json_file = os.path.abspath(
|
||||||
|
os.path.join(get_folder_path('data'), u'{}_Policy.json'.format(self.strategy.strategy_name)))
|
||||||
|
|
||||||
json_data = {}
|
json_data = {}
|
||||||
if os.path.exists(json_file):
|
if os.path.exists(json_file):
|
||||||
|
@ -45,7 +45,7 @@ class CtaPosition(CtaComponent):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def close_pos(self, direction: Direction, volume:float):
|
def close_pos(self, direction: Direction, volume: float):
|
||||||
"""平、减仓"""
|
"""平、减仓"""
|
||||||
# vol: 正整数
|
# vol: 正整数
|
||||||
|
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
""""""
|
""""""
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
import csv
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Callable
|
from typing import Any, Callable
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from copy import copy
|
from copy import copy
|
||||||
@ -19,10 +18,8 @@ from vnpy.trader.engine import BaseEngine, MainEngine
|
|||||||
from vnpy.trader.object import (
|
from vnpy.trader.object import (
|
||||||
OrderRequest,
|
OrderRequest,
|
||||||
SubscribeRequest,
|
SubscribeRequest,
|
||||||
HistoryRequest,
|
|
||||||
LogData,
|
LogData,
|
||||||
TickData,
|
TickData,
|
||||||
BarData,
|
|
||||||
ContractData
|
ContractData
|
||||||
)
|
)
|
||||||
from vnpy.trader.event import (
|
from vnpy.trader.event import (
|
||||||
@ -37,8 +34,6 @@ from vnpy.trader.event import (
|
|||||||
from vnpy.trader.constant import (
|
from vnpy.trader.constant import (
|
||||||
Direction,
|
Direction,
|
||||||
OrderType,
|
OrderType,
|
||||||
Interval,
|
|
||||||
Exchange,
|
|
||||||
Offset,
|
Offset,
|
||||||
Status
|
Status
|
||||||
)
|
)
|
||||||
@ -359,12 +354,8 @@ class CtaEngine(BaseEngine):
|
|||||||
if stop_order.vt_symbol != tick.vt_symbol:
|
if stop_order.vt_symbol != tick.vt_symbol:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
long_triggered = (
|
long_triggered = stop_order.direction == Direction.LONG and tick.last_price >= stop_order.price
|
||||||
stop_order.direction == Direction.LONG and tick.last_price >= stop_order.price
|
short_triggered = stop_order.direction == Direction.SHORT and tick.last_price <= stop_order.price
|
||||||
)
|
|
||||||
short_triggered = (
|
|
||||||
stop_order.direction == Direction.SHORT and tick.last_price <= stop_order.price
|
|
||||||
)
|
|
||||||
|
|
||||||
if long_triggered or short_triggered:
|
if long_triggered or short_triggered:
|
||||||
strategy = self.strategies[stop_order.strategy_name]
|
strategy = self.strategies[stop_order.strategy_name]
|
||||||
@ -1340,7 +1331,7 @@ class CtaEngine(BaseEngine):
|
|||||||
pos_list.append(pos)
|
pos_list.append(pos)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.write_error(u'分解SPD失败')
|
self.write_error(f'分解SPD失败:{str(ex)}')
|
||||||
|
|
||||||
# update local pos dict
|
# update local pos dict
|
||||||
self.strategy_pos_dict.update({name: pos_list})
|
self.strategy_pos_dict.update({name: pos_list})
|
||||||
@ -1439,16 +1430,21 @@ class CtaEngine(BaseEngine):
|
|||||||
Update setting file.
|
Update setting file.
|
||||||
"""
|
"""
|
||||||
strategy = self.strategies[strategy_name]
|
strategy = self.strategies[strategy_name]
|
||||||
|
# 原配置
|
||||||
strategy_config = self.strategy_setting.get('strategy_name', {})
|
old_config = self.strategy_setting.get('strategy_name', {})
|
||||||
|
new_config = {
|
||||||
self.strategy_setting[strategy_name] = {
|
|
||||||
"class_name": strategy.__class__.__name__,
|
"class_name": strategy.__class__.__name__,
|
||||||
"vt_symbol": strategy.vt_symbol,
|
"vt_symbol": strategy.vt_symbol,
|
||||||
"auto_init": auto_init,
|
"auto_init": auto_init,
|
||||||
"auto_start": auto_start,
|
"auto_start": auto_start,
|
||||||
"setting": setting
|
"setting": setting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if old_config:
|
||||||
|
self.write_log(f'{strategy_name} 配置变更:\n{old_config} \n=> \n{new_config}')
|
||||||
|
|
||||||
|
self.strategy_setting[strategy_name] = new_config
|
||||||
|
|
||||||
save_json(self.setting_filename, self.strategy_setting)
|
save_json(self.setting_filename, self.strategy_setting)
|
||||||
|
|
||||||
def remove_strategy_setting(self, strategy_name: str):
|
def remove_strategy_setting(self, strategy_name: str):
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,6 @@ from vnpy.app.cta_strategy_pro import (
|
|||||||
CtaTemplate,
|
CtaTemplate,
|
||||||
StopOrder,
|
StopOrder,
|
||||||
Direction,
|
Direction,
|
||||||
Offset,
|
|
||||||
TickData,
|
TickData,
|
||||||
BarData,
|
BarData,
|
||||||
TradeData,
|
TradeData,
|
||||||
@ -112,7 +111,7 @@ class TurtleSignalStrategy(CtaTemplate):
|
|||||||
self.send_short_orders(self.entry_down)
|
self.send_short_orders(self.entry_down)
|
||||||
|
|
||||||
cover_price = min(self.short_stop, self.exit_up)
|
cover_price = min(self.short_stop, self.exit_up)
|
||||||
ret = self.cover(cover_price, abs(self.pos), True)
|
self.cover(cover_price, abs(self.pos), True)
|
||||||
|
|
||||||
self.put_event()
|
self.put_event()
|
||||||
|
|
||||||
@ -149,7 +148,7 @@ class TurtleSignalStrategy(CtaTemplate):
|
|||||||
if self.pos >= 4:
|
if self.pos >= 4:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.cur_mi_price <= price - self.atr_value/2:
|
if self.cur_mi_price <= price - self.atr_value / 2:
|
||||||
return
|
return
|
||||||
|
|
||||||
t = self.pos / self.fixed_size
|
t = self.pos / self.fixed_size
|
||||||
|
@ -2,7 +2,6 @@ from vnpy.app.cta_strategy_pro import (
|
|||||||
CtaTemplate,
|
CtaTemplate,
|
||||||
StopOrder,
|
StopOrder,
|
||||||
Direction,
|
Direction,
|
||||||
Offset,
|
|
||||||
TickData,
|
TickData,
|
||||||
BarData,
|
BarData,
|
||||||
TradeData,
|
TradeData,
|
||||||
@ -10,7 +9,6 @@ from vnpy.app.cta_strategy_pro import (
|
|||||||
BarGenerator,
|
BarGenerator,
|
||||||
ArrayManager,
|
ArrayManager,
|
||||||
)
|
)
|
||||||
|
|
||||||
from vnpy.trader.utility import round_to
|
from vnpy.trader.utility import round_to
|
||||||
|
|
||||||
|
|
||||||
@ -189,7 +187,7 @@ class TurtleSignalStrategy_v2(CtaTemplate):
|
|||||||
self.write_log(f'买入委托编号:{refs}')
|
self.write_log(f'买入委托编号:{refs}')
|
||||||
|
|
||||||
if t == 1 and self.cur_mi_price > price:
|
if t == 1 and self.cur_mi_price > price:
|
||||||
buy_price = round_to(price + self.atr_value * 0.5 , self.symbol_price_tick)
|
buy_price = round_to(price + self.atr_value * 0.5, self.symbol_price_tick)
|
||||||
self.write_log(u'发出做多停止单,触发价格为: {}'.format(buy_price))
|
self.write_log(u'发出做多停止单,触发价格为: {}'.format(buy_price))
|
||||||
refs = self.buy(buy_price, self.invest_pos, True)
|
refs = self.buy(buy_price, self.invest_pos, True)
|
||||||
if len(refs) > 0:
|
if len(refs) > 0:
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
""""""
|
""""""
|
||||||
|
import logging
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@ -182,20 +182,24 @@ class RiskManagerEngine(BaseEngine):
|
|||||||
if vt_accountid:
|
if vt_accountid:
|
||||||
account = self.account_dict.get(vt_accountid, None)
|
account = self.account_dict.get(vt_accountid, None)
|
||||||
if account:
|
if account:
|
||||||
return account.balance, \
|
return (
|
||||||
account.available, \
|
account.balance,
|
||||||
round(account.frozen * 100 / (account.balance + 0.01), 2), \
|
account.available,
|
||||||
|
round(account.frozen * 100 / (account.balance + 0.01), 2),
|
||||||
self.percent_limit
|
self.percent_limit
|
||||||
|
)
|
||||||
if len(self.account_dict.values()) > 0:
|
if len(self.account_dict.values()) > 0:
|
||||||
account = list(self.account_dict.values())[0]
|
account = list(self.account_dict.values())[0]
|
||||||
return account.balance, \
|
return (
|
||||||
account.available, \
|
account.balance,
|
||||||
round(account.frozen * 100 / (account.balance + 0.01), 2), \
|
account.available,
|
||||||
|
round(account.frozen * 100 / (account.balance + 0.01), 2),
|
||||||
self.percent_limit
|
self.percent_limit
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return 0, 0, 0, 0
|
return 0, 0, 0, 0
|
||||||
|
|
||||||
def write_log(self, msg: str):
|
def write_log(self, msg: str, source: str = "", level: int = logging.DEBUG):
|
||||||
""""""
|
""""""
|
||||||
log = LogData(msg=msg, gateway_name="RiskManager")
|
log = LogData(msg=msg, gateway_name="RiskManager")
|
||||||
event = Event(type=EVENT_LOG, data=log)
|
event = Event(type=EVENT_LOG, data=log)
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
from .widget import ChartWidget
|
from .widget import ChartWidget, KlineWidget
|
||||||
from .item import CandleItem, VolumeItem
|
from .item import CandleItem, VolumeItem
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from typing import List, Dict, Type
|
from typing import List, Dict, Type
|
||||||
|
from collections import deque
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
|
|
||||||
from vnpy.trader.ui import QtGui, QtWidgets, QtCore
|
from vnpy.trader.ui import QtGui, QtWidgets, QtCore
|
||||||
@ -11,8 +11,7 @@ from .base import (
|
|||||||
to_int, NORMAL_FONT
|
to_int, NORMAL_FONT
|
||||||
)
|
)
|
||||||
from .axis import DatetimeAxis
|
from .axis import DatetimeAxis
|
||||||
from .item import ChartItem
|
from .item import ChartItem, CandleItem, VolumeItem
|
||||||
|
|
||||||
|
|
||||||
pg.setConfigOptions(antialias=True)
|
pg.setConfigOptions(antialias=True)
|
||||||
|
|
||||||
@ -21,10 +20,10 @@ class ChartWidget(pg.PlotWidget):
|
|||||||
""""""
|
""""""
|
||||||
MIN_BAR_COUNT = 100
|
MIN_BAR_COUNT = 100
|
||||||
|
|
||||||
def __init__(self, parent: QtWidgets.QWidget = None):
|
def __init__(self, parent: QtWidgets.QWidget = None, title: str = "ChartWidget of vn.py"):
|
||||||
""""""
|
""""""
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
self.title = title
|
||||||
self._manager: BarManager = BarManager()
|
self._manager: BarManager = BarManager()
|
||||||
|
|
||||||
self._plots: Dict[str, pg.PlotItem] = {}
|
self._plots: Dict[str, pg.PlotItem] = {}
|
||||||
@ -41,7 +40,7 @@ class ChartWidget(pg.PlotWidget):
|
|||||||
|
|
||||||
def _init_ui(self) -> None:
|
def _init_ui(self) -> None:
|
||||||
""""""
|
""""""
|
||||||
self.setWindowTitle("ChartWidget of vn.py")
|
self.setWindowTitle(self.title)
|
||||||
|
|
||||||
self._layout = pg.GraphicsLayout()
|
self._layout = pg.GraphicsLayout()
|
||||||
self._layout.setContentsMargins(10, 10, 10, 10)
|
self._layout.setContentsMargins(10, 10, 10, 10)
|
||||||
@ -119,12 +118,15 @@ class ChartWidget(pg.PlotWidget):
|
|||||||
"""
|
"""
|
||||||
Add chart item.
|
Add chart item.
|
||||||
"""
|
"""
|
||||||
|
# 创建显示的对象,蜡烛图,bar图,散点,线等
|
||||||
item = item_class(self._manager)
|
item = item_class(self._manager)
|
||||||
self._items[item_name] = item
|
self._items[item_name] = item
|
||||||
|
|
||||||
|
# 获取设置的显示区域,例如主图/volume/附图等
|
||||||
plot = self._plots.get(plot_name)
|
plot = self._plots.get(plot_name)
|
||||||
plot.addItem(item)
|
plot.addItem(item)
|
||||||
|
|
||||||
|
# 绑定显示对象与显示区域关系
|
||||||
self._item_plot_map[item] = plot
|
self._item_plot_map[item] = plot
|
||||||
|
|
||||||
def get_plot(self, plot_name: str) -> pg.PlotItem:
|
def get_plot(self, plot_name: str) -> pg.PlotItem:
|
||||||
@ -173,6 +175,7 @@ class ChartWidget(pg.PlotWidget):
|
|||||||
for item in self._items.values():
|
for item in self._items.values():
|
||||||
item.update_bar(bar)
|
item.update_bar(bar)
|
||||||
|
|
||||||
|
# 刷新显示区域的最高/最低值
|
||||||
self._update_plot_limits()
|
self._update_plot_limits()
|
||||||
|
|
||||||
if self._right_ix >= (self._manager.get_count() - self._bar_count / 2):
|
if self._right_ix >= (self._manager.get_count() - self._bar_count / 2):
|
||||||
@ -480,7 +483,9 @@ class ChartCursor(QtCore.QObject):
|
|||||||
buf[plot] += ("\n\n" + item_info_text)
|
buf[plot] += ("\n\n" + item_info_text)
|
||||||
|
|
||||||
for plot_name, plot in self._plots.items():
|
for plot_name, plot in self._plots.items():
|
||||||
plot_info_text = buf[plot]
|
plot_info_text = buf.get(plot, None)
|
||||||
|
if not plot_info_text:
|
||||||
|
continue
|
||||||
info = self._infos[plot_name]
|
info = self._infos[plot_name]
|
||||||
info.setText(plot_info_text)
|
info.setText(plot_info_text)
|
||||||
info.show()
|
info.show()
|
||||||
@ -532,3 +537,124 @@ class ChartCursor(QtCore.QObject):
|
|||||||
|
|
||||||
for label in list(self._y_labels.values()) + [self._x_label]:
|
for label in list(self._y_labels.values()) + [self._x_label]:
|
||||||
label.hide()
|
label.hide()
|
||||||
|
|
||||||
|
|
||||||
|
class KlineWidget(ChartWidget):
|
||||||
|
""" k线widget,支持多widget;主图/volume/附图"""
|
||||||
|
clsId = 0
|
||||||
|
|
||||||
|
def __init__(self, parent: QtWidgets.QWidget = None,
|
||||||
|
title: str = "kline",
|
||||||
|
display_volume: bool = False,
|
||||||
|
display_sub: bool = False):
|
||||||
|
|
||||||
|
super().__init__(parent, title)
|
||||||
|
|
||||||
|
KlineWidget.clsId += 1
|
||||||
|
self.windowId = str(KlineWidget.clsId)
|
||||||
|
|
||||||
|
# 所有K线上指标
|
||||||
|
self.main_color_pool = deque(['red', 'green', 'yellow', 'white'])
|
||||||
|
self.main_indicator_data = {} # 主图指标数据(字典,key是指标,value是list)
|
||||||
|
self.main_indicator_colors = {} # 主图指标颜色(字典,key是指标,value是list
|
||||||
|
self.main_indicator_plots = {} # 主图指标的所有画布(字典,key是指标,value是plot)
|
||||||
|
|
||||||
|
self.display_volume = display_volume
|
||||||
|
self.display_sub = display_sub
|
||||||
|
|
||||||
|
# 所有副图上指标
|
||||||
|
self.sub_color_pool = deque(['red', 'green', 'yellow', 'white'])
|
||||||
|
self.sub_indicator_data = {}
|
||||||
|
self.sub_indicator_colors = {}
|
||||||
|
self.sub_indicator_plots = {}
|
||||||
|
|
||||||
|
self.main_plot_name = f'{self.windowId}_main'
|
||||||
|
self.volume_plot_name = f'{self.windowId}_volume'
|
||||||
|
self.sub_plot_name = f'{self.windowId}_sub'
|
||||||
|
|
||||||
|
self.main_plot = None
|
||||||
|
self.volume_plot = None
|
||||||
|
self.sub_plot = None
|
||||||
|
if self.display_volume or self.display_sub:
|
||||||
|
self.add_plot(self.main_plot_name, hide_x_axis=True) # 主图
|
||||||
|
self.add_item(CandleItem, "candle", self.main_plot_name) # 往主图区域,加入
|
||||||
|
if self.display_volume:
|
||||||
|
self.add_plot(self.volume_plot_name, maximum_height=60) # volume 附图
|
||||||
|
self.add_item(VolumeItem, "volume", self.volume_plot_name)
|
||||||
|
self.volume_plot = self.get_plot(self.volume_plot_name)
|
||||||
|
if self.display_sub:
|
||||||
|
self.add_plot(self.sub_plot_name, maximum_height=180) # 附图
|
||||||
|
self.sub_plot = self.get_plot(self.sub_plot_name)
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.add_plot(self.main_plot_name, hide_x_axis=False) # 主图
|
||||||
|
self.add_item(CandleItem, "candle", self.main_plot_name) # 往主图区域,加入
|
||||||
|
self.add_cursor()
|
||||||
|
self.main_plot = self.get_plot(self.main_plot_name)
|
||||||
|
|
||||||
|
def add_indicator(self, indicator: str, is_main: bool = True):
|
||||||
|
"""
|
||||||
|
新增指标信号图
|
||||||
|
:param indicator: 指标/信号的名称,如ma10,
|
||||||
|
:param is_main: 是否为主图
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if is_main:
|
||||||
|
|
||||||
|
if indicator in self.main_indicator_plots:
|
||||||
|
self.main_plot.removeItem(self.main_indicator_plots[indicator]) # 存在该指标/信号,先移除原有画布
|
||||||
|
|
||||||
|
self.main_indicator_plots[indicator] = self.main_plot.plot() # 为该指标/信号,创建新的主图画布,登记字典
|
||||||
|
self.main_indicator_colors[indicator] = self.main_color_pool[0] # 登记该指标/信号使用的颜色
|
||||||
|
self.main_color_pool.append(self.main_color_pool.popleft()) # 调整剩余颜色
|
||||||
|
if indicator not in self.main_indicator_data:
|
||||||
|
self.main_indicator_data[indicator] = []
|
||||||
|
else:
|
||||||
|
if indicator in self.sub_indicator_plots:
|
||||||
|
self.sub_plot.removeItem(self.sub_indicator_plots[indicator]) # 若存在该指标/信号,先移除原有的附图画布
|
||||||
|
self.sub_indicator_plots[indicator] = self.sub_plot.plot() # 为该指标/信号,创建新的主图画布,登记字典
|
||||||
|
self.sub_indicator_colors[indicator] = self.sub_color_pool[0] # 登记该指标/信号使用的颜色
|
||||||
|
self.sub_color_pool.append(self.sub_color_pool.popleft()) # 调整剩余颜色
|
||||||
|
if indicator not in self.sub_indicator_data:
|
||||||
|
self.sub_indicator_data[indicator] = []
|
||||||
|
|
||||||
|
def clear_indicator(self, main=True):
|
||||||
|
"""清空指标图形"""
|
||||||
|
# 清空信号图
|
||||||
|
if main:
|
||||||
|
for indicator in self.main_indicator_plots:
|
||||||
|
self.main_plot.removeItem(self.main_indicator_plots[indicator])
|
||||||
|
self.main_indicator_data = {}
|
||||||
|
self.main_indicator_plots = {}
|
||||||
|
else:
|
||||||
|
for indicator in self.sub_indicator_plots:
|
||||||
|
self.sub_plot.removeItem(self.sub_indicator_plots[indicator])
|
||||||
|
self.sub_indicator_data = {}
|
||||||
|
self.sub_indicator_plots = {}
|
||||||
|
|
||||||
|
def plot_indicator(self, datas: dict, is_main=True, clear=False):
|
||||||
|
"""
|
||||||
|
刷新指标/信号图( 新数据)
|
||||||
|
:param datas: 所有数据
|
||||||
|
:param is_main: 是否为主图
|
||||||
|
:param clear: 是否要清除旧数据
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if clear:
|
||||||
|
self.clear_indicator(is_main) # 清除主图/副图
|
||||||
|
|
||||||
|
if is_main:
|
||||||
|
for indicator in datas:
|
||||||
|
self.add_indicator(indicator, is_main) # 逐一添加主图信号/指标
|
||||||
|
self.main_indicator_data[indicator] = datas[indicator] # 更新组件数据字典
|
||||||
|
# 调用该信号/指标画布(plotDataItem.setData()),更新数据,更新画笔颜色,更新名称
|
||||||
|
self.main_indicator_plots[indicator].setData(datas[indicator],
|
||||||
|
pen=self.main_indicator_colors[indicator][0],
|
||||||
|
name=indicator)
|
||||||
|
else:
|
||||||
|
for indicator in datas:
|
||||||
|
self.add_indicator(indicator, is_main) # 逐一增加子图指标/信号
|
||||||
|
self.sub_indicator_data[indicator] = datas[indicator] # 更新组件数据字典
|
||||||
|
# 调用该信号/指标画布(plotDataItem.setData()),更新数据,更新画笔颜色,更新名称
|
||||||
|
self.sub_indicator_plots[indicator].setData(datas[indicator],
|
||||||
|
pen=self.sub_indicator_colors[indicator][0], name=indicator)
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
|
|
||||||
HEIGHT_LIST = [3, 5, 10, 'K3', 'K5', 'K10']
|
HEIGHT_LIST = [3, 5, 10, 'K3', 'K5', 'K10']
|
||||||
|
|
||||||
FUTURE_RENKO_DB_NAME = 'FutureRenko_Db'
|
FUTURE_RENKO_DB_NAME = 'FutureRenko'
|
||||||
STOCK_RENKO_DB_NAME = 'StockRenko_Db'
|
STOCK_RENKO_DB_NAME = 'StockRenko'
|
||||||
|
@ -144,7 +144,6 @@ OPTIONTYPE_CTP2VT = {
|
|||||||
|
|
||||||
MAX_FLOAT = sys.float_info.max
|
MAX_FLOAT = sys.float_info.max
|
||||||
|
|
||||||
|
|
||||||
symbol_exchange_map = {}
|
symbol_exchange_map = {}
|
||||||
symbol_name_map = {}
|
symbol_name_map = {}
|
||||||
symbol_size_map = {}
|
symbol_size_map = {}
|
||||||
@ -790,8 +789,14 @@ class CtpTdApi(TdApi):
|
|||||||
account.close_profit = data['CloseProfit']
|
account.close_profit = data['CloseProfit']
|
||||||
account.holding_profit = data['PositionProfit']
|
account.holding_profit = data['PositionProfit']
|
||||||
account.trading_day = str(data['TradingDay'])
|
account.trading_day = str(data['TradingDay'])
|
||||||
if '-' not in account.trading_day and len(account.trading_day)== 8:
|
if '-' not in account.trading_day and len(account.trading_day) == 8:
|
||||||
account.trading_day = account.trading_day[0:4] + '-' + account.trading_day[4:6] + '-' + account.trading_day[6:8]
|
account.trading_day = '-'.join(
|
||||||
|
[
|
||||||
|
account.trading_day[0:4],
|
||||||
|
account.trading_day[4:6],
|
||||||
|
account.trading_day[6:8]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
self.gateway.on_account(account)
|
self.gateway.on_account(account)
|
||||||
|
|
||||||
@ -1121,6 +1126,7 @@ def adjust_price(price: float) -> float:
|
|||||||
price = 0
|
price = 0
|
||||||
return price
|
return price
|
||||||
|
|
||||||
|
|
||||||
class TdxMdApi():
|
class TdxMdApi():
|
||||||
"""
|
"""
|
||||||
通达信数据行情API实现
|
通达信数据行情API实现
|
||||||
@ -1745,38 +1751,58 @@ class TickCombiner(object):
|
|||||||
self.gateway.on_tick(spread_tick)
|
self.gateway.on_tick(spread_tick)
|
||||||
|
|
||||||
if self.is_ratio:
|
if self.is_ratio:
|
||||||
ratio_tick = TickData(gateway_name=self.gateway_name,
|
ratio_tick = TickData(
|
||||||
|
gateway_name=self.gateway_name,
|
||||||
symbol=self.symbol,
|
symbol=self.symbol,
|
||||||
exchange=Exchange.SPD,
|
exchange=Exchange.SPD,
|
||||||
datetime=tick.datetime)
|
datetime=tick.datetime
|
||||||
|
)
|
||||||
|
|
||||||
ratio_tick.trading_day = tick.trading_day
|
ratio_tick.trading_day = tick.trading_day
|
||||||
ratio_tick.date = tick.date
|
ratio_tick.date = tick.date
|
||||||
ratio_tick.time = tick.time
|
ratio_tick.time = tick.time
|
||||||
|
|
||||||
# 比率tick
|
# 比率tick
|
||||||
ratio_tick.ask_price_1 = round_to(target=self.price_tick,
|
ratio_tick.ask_price_1 = 100 * self.last_leg1_tick.ask_price_1 * self.leg1_ratio \
|
||||||
value=100 * self.last_leg1_tick.ask_price_1 * self.leg1_ratio / (
|
/ (self.last_leg2_tick.bid_price_1 * self.leg2_ratio) # noqa
|
||||||
self.last_leg2_tick.bid_price_1 * self.leg2_ratio))
|
ratio_tick.ask_price_1 = round_to(
|
||||||
ratio_tick.ask_volume_1 = min(self.last_leg1_tick.ask_volume_1, self.last_leg2_tick.bid_volume_1)
|
target=self.price_tick,
|
||||||
|
value=ratio_tick.ask_price_1
|
||||||
|
)
|
||||||
|
|
||||||
|
ratio_tick.ask_volume_1 = min(self.last_leg1_tick.ask_volume_1, self.last_leg2_tick.bid_volume_1)
|
||||||
|
ratio_tick.bid_price_1 = 100 * self.last_leg1_tick.bid_price_1 * self.leg1_ratio \
|
||||||
|
/ (self.last_leg2_tick.ask_price_1 * self.leg2_ratio) # noqa
|
||||||
|
ratio_tick.bid_price_1 = round_to(
|
||||||
|
target=self.price_tick,
|
||||||
|
value=ratio_tick.bid_price_1
|
||||||
|
)
|
||||||
|
|
||||||
ratio_tick.bid_price_1 = round_to(target=self.price_tick,
|
|
||||||
value=100 * self.last_leg1_tick.bid_price_1 * self.leg1_ratio / (
|
|
||||||
self.last_leg2_tick.ask_price_1 * self.leg2_ratio))
|
|
||||||
ratio_tick.bid_volume_1 = min(self.last_leg1_tick.bid_volume_1, self.last_leg2_tick.ask_volume_1)
|
ratio_tick.bid_volume_1 = min(self.last_leg1_tick.bid_volume_1, self.last_leg2_tick.ask_volume_1)
|
||||||
ratio_tick.lastPrice = round_to(target=self.price_tick,
|
ratio_tick.last_price = (ratio_tick.ask_price_1 + ratio_tick.bid_price_1) / 2
|
||||||
value=(ratio_tick.ask_price_1 + ratio_tick.bid_price_1) / 2)
|
ratio_tick.last_price = round_to(
|
||||||
|
target=self.price_tick,
|
||||||
|
value=ratio_tick.last_price
|
||||||
|
)
|
||||||
|
|
||||||
# 昨收盘价
|
# 昨收盘价
|
||||||
if self.last_leg2_tick.pre_close > 0 and self.last_leg1_tick.pre_close > 0:
|
if self.last_leg2_tick.pre_close > 0 and self.last_leg1_tick.pre_close > 0:
|
||||||
ratio_tick.pre_close = round_to(target=self.price_tick,
|
ratio_tick.pre_close = 100 * self.last_leg1_tick.pre_close * self.leg1_ratio / (
|
||||||
value=100 * self.last_leg1_tick.pre_close * self.leg1_ratio / (
|
self.last_leg2_tick.pre_close * self.leg2_ratio) # noqa
|
||||||
self.last_leg2_tick.pre_close * self.leg2_ratio))
|
ratio_tick.pre_close = round_to(
|
||||||
|
target=self.price_tick,
|
||||||
|
value=ratio_tick.pre_close
|
||||||
|
)
|
||||||
|
|
||||||
# 开盘价
|
# 开盘价
|
||||||
if self.last_leg2_tick.open_price > 0 and self.last_leg1_tick.open_price > 0:
|
if self.last_leg2_tick.open_price > 0 and self.last_leg1_tick.open_price > 0:
|
||||||
ratio_tick.open_price = round_to(target=self.price_tick,
|
ratio_tick.open_price = 100 * self.last_leg1_tick.open_price * self.leg1_ratio / (
|
||||||
value=100 * self.last_leg1_tick.open_price * self.leg1_ratio / (
|
self.last_leg2_tick.open_price * self.leg2_ratio) # noqa
|
||||||
self.last_leg2_tick.open_price * self.leg2_ratio))
|
ratio_tick.open_price = round_to(
|
||||||
|
target=self.price_tick,
|
||||||
|
value=ratio_tick.open_price
|
||||||
|
)
|
||||||
|
|
||||||
# 最高价
|
# 最高价
|
||||||
if self.ratio_high:
|
if self.ratio_high:
|
||||||
self.ratio_high = max(self.ratio_high, ratio_tick.ask_price_1)
|
self.ratio_high = max(self.ratio_high, ratio_tick.ask_price_1)
|
||||||
|
0
vnpy/task/__init__.py
Normal file
0
vnpy/task/__init__.py
Normal file
@ -40,7 +40,7 @@ print(u'Celery 使用redis配置:\nbroker:{}\nbackend:{}'.format(broker, backend
|
|||||||
app = Celery('vnpy_task', broker=broker)
|
app = Celery('vnpy_task', broker=broker)
|
||||||
|
|
||||||
# 动态导入task目录下子任务
|
# 动态导入task目录下子任务
|
||||||
app.conf.CELERY_IMPORTS = ['vnpy.task.celery_app.worker_started']
|
# app.conf.CELERY_IMPORTS = ['vnpy.task.celery_app.worker_started']
|
||||||
|
|
||||||
|
|
||||||
def worker_started():
|
def worker_started():
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"celery_broker": "amqp://admin:admin@192.168.0.202:5672//",
|
"celery_broker": "amqp://admin:admin@127.0.0.1:5672//",
|
||||||
"celery_backend": "amqp://admin:admin@192.168.0.202:5672//"
|
"celery_backend": "amqp://admin:admin@127.0.0.1:5672//"
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ from ..object import OrderRequest, SubscribeRequest
|
|||||||
from ..utility import load_json, save_json
|
from ..utility import load_json, save_json
|
||||||
from ..setting import SETTING_FILENAME, SETTINGS
|
from ..setting import SETTING_FILENAME, SETTINGS
|
||||||
|
|
||||||
|
|
||||||
COLOR_LONG = QtGui.QColor("red")
|
COLOR_LONG = QtGui.QColor("red")
|
||||||
COLOR_SHORT = QtGui.QColor("green")
|
COLOR_SHORT = QtGui.QColor("green")
|
||||||
COLOR_BID = QtGui.QColor(255, 174, 201)
|
COLOR_BID = QtGui.QColor(255, 174, 201)
|
||||||
@ -640,7 +639,7 @@ class TradingWidget(QtWidgets.QWidget):
|
|||||||
form1.addRow("方向", self.direction_combo)
|
form1.addRow("方向", self.direction_combo)
|
||||||
form1.addRow("开平", self.offset_combo)
|
form1.addRow("开平", self.offset_combo)
|
||||||
form1.addRow("类型", self.order_type_combo)
|
form1.addRow("类型", self.order_type_combo)
|
||||||
form1.addRow( self.checkFixed, self.price_line)
|
form1.addRow(self.checkFixed, self.price_line)
|
||||||
form1.addRow("数量", self.volume_line)
|
form1.addRow("数量", self.volume_line)
|
||||||
form1.addRow("接口", self.gateway_combo)
|
form1.addRow("接口", self.gateway_combo)
|
||||||
form1.addRow(send_button)
|
form1.addRow(send_button)
|
||||||
@ -899,8 +898,6 @@ class TradingWidget(QtWidgets.QWidget):
|
|||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.main_engine.write_log(u'tradingWg.autoFillSymbol exception:{}'.format(str(ex)))
|
self.main_engine.write_log(u'tradingWg.autoFillSymbol exception:{}'.format(str(ex)))
|
||||||
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def close_position(self, cell):
|
def close_position(self, cell):
|
||||||
"""根据持仓信息自动填写交易组件"""
|
"""根据持仓信息自动填写交易组件"""
|
||||||
try:
|
try:
|
||||||
@ -926,13 +923,14 @@ class TradingWidget(QtWidgets.QWidget):
|
|||||||
self.volume_line.setText(str(pos.volume))
|
self.volume_line.setText(str(pos.volume))
|
||||||
|
|
||||||
if pos.direction in [Direction.LONG, Direction.NET]:
|
if pos.direction in [Direction.LONG, Direction.NET]:
|
||||||
self.direction_combo.setCurrentText(Direction.SHORT)
|
self.direction_combo.setCurrentText(Direction.SHORT.value)
|
||||||
else:
|
else:
|
||||||
self.direction_combo.setCurrentText(Direction.LONG)
|
self.direction_combo.setCurrentText(Direction.LONG.value)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
self.main_engine.write_log(u'tradingWg.closePosition exception:{}'.format(str(ex)))
|
self.main_engine.write_log(u'tradingWg.closePosition exception:{}'.format(str(ex)))
|
||||||
|
|
||||||
|
|
||||||
class ActiveOrderMonitor(OrderMonitor):
|
class ActiveOrderMonitor(OrderMonitor):
|
||||||
"""
|
"""
|
||||||
Monitor which shows active order only.
|
Monitor which shows active order only.
|
||||||
|
@ -612,6 +612,7 @@ def display_dual_axis(df, columns1, columns2=[], invert_yaxis1=False, invert_yax
|
|||||||
else:
|
else:
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
class BarGenerator:
|
class BarGenerator:
|
||||||
"""
|
"""
|
||||||
For:
|
For:
|
||||||
@ -1225,7 +1226,7 @@ def get_bars(csv_file: str,
|
|||||||
symbol: str,
|
symbol: str,
|
||||||
exchange: Exchange,
|
exchange: Exchange,
|
||||||
start_date: datetime = None,
|
start_date: datetime = None,
|
||||||
end_date: datetime = None,):
|
end_date: datetime = None, ):
|
||||||
"""
|
"""
|
||||||
获取bar
|
获取bar
|
||||||
数据存储目录: 项目/bar_data
|
数据存储目录: 项目/bar_data
|
||||||
|
1
win_clean_celery_jobs.bat
Normal file
1
win_clean_celery_jobs.bat
Normal file
@ -0,0 +1 @@
|
|||||||
|
celery -A vnpy.task.celery_app purge
|
1
win_start_celery_worker.bat
Normal file
1
win_start_celery_worker.bat
Normal file
@ -0,0 +1 @@
|
|||||||
|
celery worker -c 2 -A vnpy.task.celery_app -P eventlet -l debug -f celery.log
|
Loading…
Reference in New Issue
Block a user