数字货币跨市场套利(搬砖)引擎
This commit is contained in:
parent
e5be9ba35f
commit
a36c3d338e
20
vnpy/trader/app/cmaStrategy/CMA_setting.json
Normal file
20
vnpy/trader/app/cmaStrategy/CMA_setting.json
Normal file
@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"name": "S45_BINANCE_FCOIN",
|
||||
"className": "Strategy45",
|
||||
"vtSymbol": "btc_usdt",
|
||||
"master_exchange":"BINANCE",
|
||||
"slave_exchange":"FCOIN",
|
||||
"master_gateway":"BINANCE_2",
|
||||
"slave_gateway":"FCOIN_3",
|
||||
"baseUpLine":10,
|
||||
"baseMidLine":0,
|
||||
"baseDnLine":-10,
|
||||
"minDiff":0.01,
|
||||
"inputSS":0.01,
|
||||
"min_trade_size":0.002,
|
||||
"mode":"tick",
|
||||
"auto_init": true,
|
||||
"auto_start": true
|
||||
}
|
||||
]
|
10
vnpy/trader/app/cmaStrategy/__init__.py
Normal file
10
vnpy/trader/app/cmaStrategy/__init__.py
Normal file
@ -0,0 +1,10 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
from vnpy.trader.app.cmaStrategy.cmaEngine import CmaEngine
|
||||
from vnpy.trader.app.cmaStrategy.uiCmaWidget import CmaEngineManager
|
||||
|
||||
appName = 'CrossMarketArbitrage'
|
||||
appDisplayName = u'跨市场套利'
|
||||
appEngine = CmaEngine
|
||||
appWidget = CmaEngineManager
|
||||
appIco = 'cma.ico'
|
1996
vnpy/trader/app/cmaStrategy/cmaEngine.py
Normal file
1996
vnpy/trader/app/cmaStrategy/cmaEngine.py
Normal file
File diff suppressed because it is too large
Load Diff
309
vnpy/trader/app/cmaStrategy/cmaTemplate.py
Normal file
309
vnpy/trader/app/cmaStrategy/cmaTemplate.py
Normal file
@ -0,0 +1,309 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
'''
|
||||
本文件包含了CTA引擎中的策略开发用模板,开发策略时需要继承CtaTemplate类。
|
||||
'''
|
||||
|
||||
from datetime import datetime,timedelta
|
||||
import os,csv
|
||||
from vnpy.trader.app.ctaStrategy.ctaBase import *
|
||||
from vnpy.trader.vtConstant import *
|
||||
|
||||
|
||||
########################################################################
|
||||
class CmaTemplate(object):
|
||||
"""跨市场套利策略模板"""
|
||||
|
||||
# 策略类的名称和作者
|
||||
className = 'CmaTemplate'
|
||||
author = u'李来佳'
|
||||
|
||||
# 策略的基本参数
|
||||
name = 'StrategyName' # 策略实例名称
|
||||
vtSymbol = EMPTY_STRING # 交易的合约vt系统代码
|
||||
symbol = EMPTY_STRING # 交易的合约代码
|
||||
|
||||
base_symbol = EMPTY_STRING # 交易主货币
|
||||
quote_symbol = EMPTY_STRING # 基准货币
|
||||
master_symbol = EMPTY_STRING # 主交易所币对
|
||||
slave_symbol = EMPTY_STRING # 从交易所币对
|
||||
|
||||
master_exchange = EMPTY_STRING # 主交易所
|
||||
slave_exchange = EMPTY_STRING # 次交易所
|
||||
|
||||
master_gateway = EMPTY_STRING # 主交易所网关
|
||||
slave_gateway = EMPTY_STRING # 次交易所网关
|
||||
|
||||
# 策略的基本变量,由引擎管理
|
||||
inited = False # 是否进行了初始化
|
||||
trading = False # 是否启动交易,由引擎管理
|
||||
backtesting = False # 是否回测
|
||||
|
||||
# 参数列表,保存了参数的名称
|
||||
paramList = ['name',
|
||||
'className',
|
||||
'author',
|
||||
'vtSymbol',
|
||||
'master_exchange',
|
||||
'slave_exchange',
|
||||
'master_gateway',
|
||||
'slave_gateway'
|
||||
]
|
||||
|
||||
# 变量列表,保存了变量的名称
|
||||
varList = ['inited',
|
||||
'trading',
|
||||
'master_entrust',
|
||||
'slave_entrust']
|
||||
|
||||
tradingOpen = True # 允许开仓
|
||||
forceTradingClose = False # 强制平仓标志
|
||||
delayMission = [] # 延迟的任务
|
||||
position = None # 持仓
|
||||
|
||||
is_7x24 = True # 是否7x24运行
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def __init__(self, cmaEngine, setting):
|
||||
"""Constructor"""
|
||||
self.cmaEngine = cmaEngine
|
||||
|
||||
# 委托单状态
|
||||
self.master_entrust = 0 # 0 表示没有委托,1 表示存在多仓的委托,-1 表示存在空仓的委托
|
||||
self.slave_entrust = 0 # 0 表示没有委托,1 表示存在多仓的委托,-1 表示存在空仓的委托
|
||||
|
||||
# 保存委托单编号和相关委托单的字典
|
||||
# key为委托单编号
|
||||
# value为该合约相关的委托单
|
||||
self.uncompletedOrders = {}
|
||||
|
||||
# 设置策略的参数
|
||||
if setting:
|
||||
self.writeCtaLog(u'基类设置参数')
|
||||
d = self.__dict__
|
||||
for key in self.paramList:
|
||||
if key in setting:
|
||||
d[key] = setting[key]
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def onInit(self):
|
||||
"""初始化策略(必须由用户继承实现)"""
|
||||
raise NotImplementedError
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def onStart(self):
|
||||
"""启动策略(必须由用户继承实现)"""
|
||||
raise NotImplementedError
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def onStop(self):
|
||||
"""停止策略(必须由用户继承实现)"""
|
||||
raise NotImplementedError
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def onTick(self, tick):
|
||||
"""收到行情TICK推送(必须由用户继承实现)"""
|
||||
raise NotImplementedError
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def onOrder(self, order):
|
||||
"""收到委托变化推送(必须由用户继承实现)"""
|
||||
raise NotImplementedError
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def onTrade(self, trade):
|
||||
"""收到成交推送(必须由用户继承实现)"""
|
||||
raise NotImplementedError
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBar(self, bar):
|
||||
"""收到Bar推送(必须由用户继承实现)"""
|
||||
raise NotImplementedError
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def cancelOrder(self, vtOrderID):
|
||||
"""撤单"""
|
||||
|
||||
# 如果发单号为空字符串,则不进行后续操作
|
||||
if not vtOrderID or vtOrderID == '':
|
||||
return
|
||||
|
||||
if STOPORDERPREFIX in vtOrderID:
|
||||
self.cmaEngine.cancelStopOrder(vtOrderID)
|
||||
else:
|
||||
self.cmaEngine.cancelOrder(vtOrderID)
|
||||
|
||||
def saveData(self):
|
||||
"""保持bar数据"""
|
||||
pass
|
||||
|
||||
def onTimer(self):
|
||||
"""定时执行任务
|
||||
由mainEngine驱动"""
|
||||
pass
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def setParam(self, setting):
|
||||
"""设置参数"""
|
||||
self.writeCtaLog(u'使用参数:{}'.format(setting))
|
||||
d = self.__dict__
|
||||
for key in self.paramList:
|
||||
if key in setting:
|
||||
d[key] = setting[key]
|
||||
# ----------------------------------------------------------------------
|
||||
def writeCtaLog(self, content):
|
||||
"""记录CTA日志"""
|
||||
try:
|
||||
self.cmaEngine.writeCtaLog(content, strategy_name=self.name)
|
||||
except Exception as ex:
|
||||
content = self.name + ':' + content
|
||||
self.cmaEngine.writeCtaLog(content)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def writeCtaError(self, content):
|
||||
"""记录CTA出错日志"""
|
||||
try:
|
||||
self.cmaEngine.writeCtaError(content, strategy_name=self.name)
|
||||
except Exception as ex:
|
||||
content = self.name + ':' + content
|
||||
self.cmaEngine.writeCtaError(content)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def writeCtaWarning(self, content):
|
||||
"""记录CTA告警日志"""
|
||||
try:
|
||||
self.cmaEngine.writeCtaWarning(content, strategy_name=self.name)
|
||||
except Exception as ex:
|
||||
content = self.name + ':' + content
|
||||
self.cmaEngine.writeCtaWarning(content)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def writeCtaNotification(self, content):
|
||||
"""记录CTA通知日志"""
|
||||
content = self.name + ':' + content
|
||||
|
||||
if not self.backtesting:
|
||||
self.cmaEngine.writeCtaNotification(content)
|
||||
else:
|
||||
self.cmaEngine.writeCtaLog(content)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def writeCtaCritical(self, content):
|
||||
"""记录CTA系统异常日志"""
|
||||
|
||||
if not self.backtesting:
|
||||
try:
|
||||
self.cmaEngine.writeCtaCritical(content,strategy_name=self.name)
|
||||
except Exception as ex:
|
||||
content = self.name + ':' + content
|
||||
self.cmaEngine.writeCtaCritical(content)
|
||||
else:
|
||||
content = self.name + ':' + content
|
||||
self.cmaEngine.writeCtaError(content)
|
||||
|
||||
def sendSignal(self,direction,price, level):
|
||||
"""发送信号通知"""
|
||||
try:
|
||||
if not self.backtesting:
|
||||
self.cmaEngine.sendCtaSignal(source=self.name, symbol=self.vtSymbol, direction=direction, price=price, level=level)
|
||||
|
||||
except Exception as ex:
|
||||
self.writeCtaError(u'sendSignal Exception:{0}'.format(str(ex)))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def putEvent(self):
|
||||
"""发出策略状态变化事件"""
|
||||
self.cmaEngine.putStrategyEvent(self.name)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getEngineType(self):
|
||||
"""查询当前运行的环境"""
|
||||
return self.cmaEngine.engineType
|
||||
|
||||
def append_data(self, file_name, dict_data, field_names=None):
|
||||
"""
|
||||
添加数据到csv文件中
|
||||
:param file_name: csv的文件全路径
|
||||
:param dict_data: OrderedDict
|
||||
:return:
|
||||
"""
|
||||
if not isinstance(dict_data, dict):
|
||||
self.writeCtaError(u'append_data,输入数据不是dict')
|
||||
return
|
||||
|
||||
dict_fieldnames = list(dict_data.keys()) if field_names is None else field_names
|
||||
|
||||
if not isinstance(dict_fieldnames, list):
|
||||
self.writeCtaError(u'append_data,输入字段不是list')
|
||||
return
|
||||
try:
|
||||
if not os.path.exists(file_name):
|
||||
self.writeCtaLog(u'create csv file:{}'.format(file_name))
|
||||
with open(file_name, 'a', encoding='utf8', newline='') as csvWriteFile:
|
||||
writer = csv.DictWriter(f=csvWriteFile, fieldnames=dict_fieldnames, dialect='excel')
|
||||
self.writeCtaLog(u'write csv header:{}'.format(dict_fieldnames))
|
||||
writer.writeheader()
|
||||
writer.writerow(dict_data)
|
||||
else:
|
||||
with open(file_name, 'a', encoding='utf8', newline='') as csvWriteFile:
|
||||
writer = csv.DictWriter(f=csvWriteFile, fieldnames=dict_fieldnames, dialect='excel')
|
||||
writer.writerow(dict_data)
|
||||
except Exception as ex:
|
||||
self.writeCtaError(u'append_data exception:{}'.format(str(ex)))
|
||||
|
||||
|
||||
def checkExistDelayMission(self, func):
|
||||
if len(self.delayMission) == 0:
|
||||
return False
|
||||
|
||||
for mission in self.delayMission:
|
||||
if 'func' in mission and mission['func'] == func:
|
||||
return True
|
||||
return False
|
||||
|
||||
def cancelForceClose(self):
|
||||
"""
|
||||
取消强制平仓
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
def forceCloseAllPos(self):
|
||||
"""
|
||||
策略实现上层调度,强制平所有仓位,不再开仓
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
def forceOpenPos(self, longPos, shortPos):
|
||||
"""
|
||||
策略实现上层调度,强制开仓
|
||||
:param longPos: 对应开仓的多单[{"price": 2560, volume": 77, "symbol": "RB99", "margin": -953, "direction": "long" }]
|
||||
:param shortPos: 对应开仓的空单[{"price": 2560, volume": 77, "symbol": "RB99", "margin": -953, "direction": "short" }]
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
def cancelAllOrders(self):
|
||||
"""
|
||||
撤销所有委托
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
def getPositions(self):
|
||||
"""
|
||||
获取策略当前持仓
|
||||
:return: [{'vtSymbol':symbol,'direction':direction,'volume':volume]
|
||||
"""
|
||||
if not self.position:
|
||||
return []
|
||||
l = []
|
||||
if self.position.longPos > 0:
|
||||
l.append({'vtSymbol': self.vtSymbol, 'direction': DIRECTION_LONG, 'volume': self.position.longPos})
|
||||
|
||||
if abs(self.position.shortPos) > 0:
|
||||
l.append({'vtSymbol': self.vtSymbol, 'direction': DIRECTION_SHORT, 'volume': abs(self.position.shortPos)})
|
||||
|
||||
self.writeCtaLog(u'当前持仓:{}'.format(l))
|
||||
return l
|
13
vnpy/trader/app/cmaStrategy/language/__init__.py
Normal file
13
vnpy/trader/app/cmaStrategy/language/__init__.py
Normal file
@ -0,0 +1,13 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
import json
|
||||
import os
|
||||
import traceback
|
||||
|
||||
# 默认设置
|
||||
from vnpy.trader.app.cmaStrategy.language.chinese import text
|
||||
|
||||
# 是否要使用英文
|
||||
from vnpy.trader.vtGlobal import globalSetting
|
||||
if globalSetting['language'] == 'english':
|
||||
from vnpy.trader.app.cmaStrategy.language.english import text
|
19
vnpy/trader/app/cmaStrategy/language/chinese/text.py
Normal file
19
vnpy/trader/app/cmaStrategy/language/chinese/text.py
Normal file
@ -0,0 +1,19 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
INIT = u'初始化'
|
||||
START = u'启动'
|
||||
STOP = u'停止'
|
||||
FORCEINIT = u'强制初始化'
|
||||
|
||||
CMA_ENGINE_STARTED = u'跨市场套利引擎启动成功'
|
||||
|
||||
CMA_STRATEGY = u'CMA策略'
|
||||
LOAD_STRATEGY = u'加载策略'
|
||||
INIT_ALL = u'全部初始化'
|
||||
START_ALL = u'全部启动'
|
||||
STOP_ALL = u'全部停止'
|
||||
SAVE_POSITION_DATA = u'保存持仓'
|
||||
|
||||
STRATEGY_LOADED = u'策略加载成功'
|
||||
|
||||
SAVE_POSITION_QUESTION = u'是否要保存策略持仓数据到数据库?'
|
20
vnpy/trader/app/cmaStrategy/language/english/text.py
Normal file
20
vnpy/trader/app/cmaStrategy/language/english/text.py
Normal file
@ -0,0 +1,20 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
INIT = u'Init'
|
||||
START = u'Start'
|
||||
STOP = u'Stop'
|
||||
FORCEINIT = u'ForceInit'
|
||||
|
||||
|
||||
CMA_ENGINE_STARTED = u'Cross Market Abitrage engine started.'
|
||||
|
||||
CMA_STRATEGY = u'CMA Strategy'
|
||||
LOAD_STRATEGY = u'Load Strategy'
|
||||
INIT_ALL = u'Init All'
|
||||
START_ALL = u'Start All'
|
||||
STOP_ALL = u'Stop All'
|
||||
SAVE_POSITION_DATA = u'Save Position Data'
|
||||
|
||||
STRATEGY_LOADED = u'Strategy loaded.'
|
||||
|
||||
SAVE_POSITION_QUESTION = u'Do you want to save strategy position data into database?'
|
51
vnpy/trader/app/cmaStrategy/strategy/__init__.py
Normal file
51
vnpy/trader/app/cmaStrategy/strategy/__init__.py
Normal file
@ -0,0 +1,51 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
'''
|
||||
动态载入所有的策略类,先从vnpy/trader/app/ctaStrategy/strategy下加载,其次,从工作目录下strategy加载。
|
||||
如果重复,工作目录的strategy优先。
|
||||
'''
|
||||
|
||||
import os
|
||||
import importlib
|
||||
|
||||
import traceback
|
||||
|
||||
# 用来保存策略类的字典
|
||||
ARBITRAGE_STRATEGY_CLASS = {}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def loadStrategyModule(moduleName):
|
||||
"""使用importlib动态载入模块"""
|
||||
try:
|
||||
print('loading {0}'.format(moduleName))
|
||||
module = importlib.import_module(moduleName)
|
||||
|
||||
# 遍历模块下的对象,只有名称中包含'Strategy'的才是策略类
|
||||
for k in dir(module):
|
||||
if 'Strategy' in k:
|
||||
print('adding {} into STRATEGY_CLASS'.format(k))
|
||||
v = module.__getattribute__(k)
|
||||
if k in ARBITRAGE_STRATEGY_CLASS:
|
||||
print('Replace strategy {} with {}'.format(k,moduleName))
|
||||
ARBITRAGE_STRATEGY_CLASS[k] = v
|
||||
except Exception as ex:
|
||||
print('-' * 20)
|
||||
print('Failed to import strategy file %s:' % moduleName)
|
||||
print('Exception:{},{}'.format(str(ex),traceback.format_exc()))
|
||||
|
||||
# 获取目录路径
|
||||
path = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
print('init strategies from {}'.format(path))
|
||||
|
||||
# 遍历strategy目录下的文件
|
||||
for root, subdirs, files in os.walk(path):
|
||||
for name in files:
|
||||
# 只有文件名中包含strategy且非.pyc的文件,才是策略文件
|
||||
if 'strategy' in name and '.pyc' not in name:
|
||||
# 模块名称需要上前缀
|
||||
moduleName = 'vnpy.trader.app.cmaStrategy.strategy.' + name.replace('.py', '')
|
||||
loadStrategyModule(moduleName)
|
||||
|
||||
|
||||
print('finished load arbitrage strategy modules')
|
305
vnpy/trader/app/cmaStrategy/uiCmaWidget.py
Normal file
305
vnpy/trader/app/cmaStrategy/uiCmaWidget.py
Normal file
@ -0,0 +1,305 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
'''
|
||||
CMA模块相关的GUI控制组件
|
||||
'''
|
||||
|
||||
|
||||
import os
|
||||
from time import sleep
|
||||
import traceback
|
||||
|
||||
from vnpy.trader.app.cmaStrategy.language import text
|
||||
from vnpy.trader.uiBasicWidget import QtWidgets, QtGui, QtCore, BasicCell
|
||||
from vnpy.trader.vtEvent import *
|
||||
from vnpy.trader.app.cmaStrategy.strategy import *
|
||||
|
||||
########################################################################
|
||||
class CmaValueMonitor(QtWidgets.QTableWidget):
|
||||
"""参数监控"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, parent=None):
|
||||
"""Constructor"""
|
||||
super(CmaValueMonitor, self).__init__(parent)
|
||||
|
||||
self.keyCellDict = {}
|
||||
self.data = None
|
||||
self.inited = False
|
||||
|
||||
self.initUi()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def initUi(self):
|
||||
"""初始化界面"""
|
||||
self.setRowCount(1)
|
||||
self.verticalHeader().setVisible(False)
|
||||
self.setEditTriggers(self.NoEditTriggers)
|
||||
|
||||
self.setMaximumHeight(self.sizeHint().height())
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def updateData(self, data):
|
||||
"""更新数据"""
|
||||
if not self.inited:
|
||||
# 设置标题
|
||||
|
||||
self.setColumnCount(len(data))
|
||||
self.setHorizontalHeaderLabels(data.keys())
|
||||
|
||||
# 新增数据
|
||||
col = 0
|
||||
for k, v in data.items():
|
||||
cell = QtWidgets.QTableWidgetItem(v)
|
||||
self.keyCellDict[k] = cell
|
||||
self.setItem(0, col, cell)
|
||||
col += 1
|
||||
|
||||
self.inited = True
|
||||
else:
|
||||
# 更新数据
|
||||
for k, v in data.items():
|
||||
cell = self.keyCellDict[k]
|
||||
cell.setText(str(v))
|
||||
|
||||
#cell.setBackgroundColor()
|
||||
|
||||
# 调整表格宽度为自适应
|
||||
self.resizeColumnsToContents()
|
||||
self.resizeRowsToContents()
|
||||
|
||||
########################################################################
|
||||
class CmaStrategyManager(QtWidgets.QGroupBox):
|
||||
"""策略管理组件"""
|
||||
signal = QtCore.Signal(type(Event()))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, cmaEngine, eventEngine, name, parent=None):
|
||||
"""Constructor"""
|
||||
super(CmaStrategyManager, self).__init__(parent)
|
||||
|
||||
self.cmaEngine = cmaEngine
|
||||
self.eventEngine = eventEngine
|
||||
self.name = name
|
||||
|
||||
self.initUi()
|
||||
self.updateMonitor()
|
||||
self.registerEvent()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def initUi(self):
|
||||
"""初始化界面"""
|
||||
self.setTitle(self.name)
|
||||
|
||||
self.paramMonitor = CmaValueMonitor(self) # 参数监控
|
||||
self.varMonitor = CmaValueMonitor(self) # 变量监控
|
||||
|
||||
height = 80
|
||||
self.paramMonitor.setFixedHeight(height)
|
||||
self.varMonitor.setFixedHeight(height)
|
||||
|
||||
buttonInit = QtWidgets.QPushButton(text.INIT)
|
||||
buttonStart = QtWidgets.QPushButton(text.START)
|
||||
buttonStop = QtWidgets.QPushButton(text.STOP)
|
||||
buttonInitForce = QtWidgets.QPushButton(text.FORCEINIT)
|
||||
buttonInit.clicked.connect(self.init)
|
||||
buttonStart.clicked.connect(self.start)
|
||||
buttonStop.clicked.connect(self.stop)
|
||||
buttonInitForce.clicked.connect(self.initForce)
|
||||
|
||||
hbox1 = QtWidgets.QHBoxLayout()
|
||||
hbox1.addWidget(buttonInit)
|
||||
hbox1.addWidget(buttonStart)
|
||||
hbox1.addWidget(buttonStop)
|
||||
hbox1.addWidget(buttonInitForce)
|
||||
|
||||
hbox1.addStretch()
|
||||
|
||||
hbox2 = QtWidgets.QHBoxLayout()
|
||||
hbox2.addWidget(self.paramMonitor)
|
||||
|
||||
hbox3 = QtWidgets.QHBoxLayout()
|
||||
hbox3.addWidget(self.varMonitor)
|
||||
|
||||
vbox = QtWidgets.QVBoxLayout()
|
||||
vbox.addLayout(hbox1)
|
||||
vbox.addLayout(hbox2)
|
||||
vbox.addLayout(hbox3)
|
||||
|
||||
self.setLayout(vbox)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def updateMonitor(self, event=None):
|
||||
"""显示策略最新状态"""
|
||||
|
||||
# 获取策略的参数目录
|
||||
paramDict = self.cmaEngine.getStrategyParam(self.name)
|
||||
if paramDict:
|
||||
self.paramMonitor.updateData(paramDict)
|
||||
|
||||
# 获取策略的变量目录
|
||||
varDict = self.cmaEngine.getStrategyVar(self.name)
|
||||
if varDict:
|
||||
self.varMonitor.updateData(varDict)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def registerEvent(self):
|
||||
"""注册事件监听"""
|
||||
|
||||
# 绑定事件的更新函数为updateMonitor
|
||||
self.signal.connect(self.updateMonitor)
|
||||
|
||||
# 注册事件
|
||||
self.eventEngine.register(EVENT_CTA_STRATEGY+self.name, self.signal.emit)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def init(self):
|
||||
"""初始化策略"""
|
||||
self.cmaEngine.initStrategy(self.name)
|
||||
|
||||
def initForce(self):
|
||||
"""强制初始化策略"""
|
||||
self.cmaEngine.initStrategy(self.name, force = True)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def start(self):
|
||||
"""启动策略"""
|
||||
self.cmaEngine.startStrategy(self.name)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def stop(self):
|
||||
"""停止策略"""
|
||||
self.cmaEngine.stopStrategy(self.name)
|
||||
|
||||
|
||||
########################################################################
|
||||
class CmaEngineManager(QtWidgets.QWidget):
|
||||
"""CTA引擎管理组件"""
|
||||
signal = QtCore.Signal(type(Event()))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, cmaEngine, eventEngine, parent=None):
|
||||
"""Constructor"""
|
||||
super(CmaEngineManager, self).__init__(parent)
|
||||
|
||||
self.cmaEngine = cmaEngine
|
||||
self.eventEngine = eventEngine
|
||||
|
||||
self.strategyLoaded = False
|
||||
|
||||
self.initUi()
|
||||
self.registerEvent()
|
||||
|
||||
# 记录日志
|
||||
self.cmaEngine.writeCtaLog(text.CMA_ENGINE_STARTED)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def initUi(self):
|
||||
"""初始化界面"""
|
||||
self.setWindowTitle(u'Cross Market Arbitrage')
|
||||
|
||||
# 按钮
|
||||
loadButton = QtWidgets.QPushButton(text.LOAD_STRATEGY)
|
||||
initAllButton = QtWidgets.QPushButton(text.INIT_ALL)
|
||||
startAllButton = QtWidgets.QPushButton(text.START_ALL)
|
||||
stopAllButton = QtWidgets.QPushButton(text.STOP_ALL)
|
||||
savePositionButton = QtWidgets.QPushButton(text.SAVE_POSITION_DATA)
|
||||
|
||||
loadButton.clicked.connect(self.load)
|
||||
initAllButton.clicked.connect(self.initAll)
|
||||
startAllButton.clicked.connect(self.startAll)
|
||||
stopAllButton.clicked.connect(self.stopAll)
|
||||
|
||||
# 滚动区域,放置所有的CtaStrategyManager
|
||||
self.scrollArea = QtWidgets.QScrollArea()
|
||||
self.scrollArea.setWidgetResizable(True)
|
||||
|
||||
# CTA组件的日志监控
|
||||
self.cmaLogMonitor = QtWidgets.QTextEdit()
|
||||
self.cmaLogMonitor.setReadOnly(True)
|
||||
self.cmaLogMonitor.setMaximumHeight(200)
|
||||
|
||||
# 设置布局
|
||||
hbox2 = QtWidgets.QHBoxLayout()
|
||||
hbox2.addWidget(loadButton)
|
||||
hbox2.addWidget(initAllButton)
|
||||
hbox2.addWidget(startAllButton)
|
||||
hbox2.addWidget(stopAllButton)
|
||||
hbox2.addWidget(savePositionButton)
|
||||
hbox2.addStretch()
|
||||
|
||||
vbox = QtWidgets.QVBoxLayout()
|
||||
vbox.addLayout(hbox2)
|
||||
vbox.addWidget(self.scrollArea)
|
||||
vbox.addWidget(self.cmaLogMonitor)
|
||||
self.setLayout(vbox)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def initStrategyManager(self):
|
||||
"""初始化策略管理组件界面"""
|
||||
w = QtWidgets.QWidget()
|
||||
vbox = QtWidgets.QVBoxLayout()
|
||||
|
||||
for name in self.cmaEngine.strategyDict.keys():
|
||||
# 为每一个策略实例,创建对应的管理组件实例
|
||||
strategyManager = CmaStrategyManager(self.cmaEngine, self.eventEngine, name)
|
||||
vbox.addWidget(strategyManager)
|
||||
sleep(0.2)
|
||||
|
||||
vbox.addStretch()
|
||||
|
||||
w.setLayout(vbox)
|
||||
self.scrollArea.setWidget(w)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def initAll(self):
|
||||
"""全部初始化"""
|
||||
for name in self.cmaEngine.strategyDict.keys():
|
||||
self.cmaEngine.initStrategy(name)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def startAll(self):
|
||||
"""全部启动"""
|
||||
for name in self.cmaEngine.strategyDict.keys():
|
||||
self.cmaEngine.startStrategy(name)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def stopAll(self):
|
||||
"""全部停止"""
|
||||
for name in self.cmaEngine.strategyDict.keys():
|
||||
self.cmaEngine.stopStrategy(name)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def load(self):
|
||||
"""加载策略"""
|
||||
if not self.strategyLoaded:
|
||||
try:
|
||||
self.cmaEngine.loadSetting()
|
||||
self.initStrategyManager()
|
||||
self.strategyLoaded = True
|
||||
self.cmaEngine.writeCtaLog(text.STRATEGY_LOADED)
|
||||
except Exception as ex:
|
||||
self.cmaEngine.writeCtaError(str(ex))
|
||||
traceback.print_exc()
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def updateCtaLog(self, event):
|
||||
"""更新CTA相关日志"""
|
||||
log = event.dict_['data']
|
||||
content = '\t'.join([log.logTime, log.logContent])
|
||||
self.cmaLogMonitor.append(content)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def registerEvent(self):
|
||||
"""注册事件监听"""
|
||||
self.signal.connect(self.updateCtaLog)
|
||||
self.eventEngine.register(EVENT_CTA_LOG, self.signal.emit)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user