[Add]新增FutuTrader,修改futuGateway兼容Python3新版
This commit is contained in:
parent
9f5b786d1e
commit
1c5abeb986
19
examples/FutuTrader/CTA_setting.json
Normal file
19
examples/FutuTrader/CTA_setting.json
Normal file
@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"name": "double ema",
|
||||
"className": "DoubleMaStrategy",
|
||||
"vtSymbol": "rb1805"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "atr rsi",
|
||||
"className": "AtrRsiStrategy",
|
||||
"vtSymbol": "IC1802"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "king keltner",
|
||||
"className": "KkStrategy",
|
||||
"vtSymbol": "IH1802"
|
||||
}
|
||||
]
|
7
examples/FutuTrader/Futu_connect.json
Normal file
7
examples/FutuTrader/Futu_connect.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": 11111,
|
||||
"market": "US",
|
||||
"password": "123123",
|
||||
"env": "REAL"
|
||||
}
|
10
examples/FutuTrader/RM_setting.json
Normal file
10
examples/FutuTrader/RM_setting.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"active": false,
|
||||
"orderFlowLimit": 50,
|
||||
"orderFlowClear": 1,
|
||||
"orderSizeLimit": 100,
|
||||
"tradeLimit": 1000,
|
||||
"workingOrderLimit": 20,
|
||||
"orderCancelLimit": 10,
|
||||
"marginRatioLimit": 0.85
|
||||
}
|
20
examples/FutuTrader/VT_setting.json
Normal file
20
examples/FutuTrader/VT_setting.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"fontFamily": "微软雅黑",
|
||||
"fontSize": 12,
|
||||
|
||||
"mongoHost": "localhost",
|
||||
"mongoPort": 27017,
|
||||
"mongoLogging": true,
|
||||
|
||||
"darkStyle": true,
|
||||
"language": "chinese",
|
||||
|
||||
"logActive": true,
|
||||
"logLevel": "debug",
|
||||
"logConsole": true,
|
||||
"logFile": true,
|
||||
|
||||
"tdPenalty": ["IF", "IH", "IC"],
|
||||
|
||||
"maxDecimal": 4
|
||||
}
|
46
examples/FutuTrader/run.py
Normal file
46
examples/FutuTrader/run.py
Normal file
@ -0,0 +1,46 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
import sys
|
||||
|
||||
# vn.trader模块
|
||||
from vnpy.event import EventEngine
|
||||
from vnpy.trader.vtEngine import MainEngine
|
||||
from vnpy.trader.uiQt import createQApp
|
||||
from vnpy.trader.uiMainWindow import MainWindow
|
||||
|
||||
# 加载底层接口
|
||||
from vnpy.trader.gateway import futuGateway
|
||||
|
||||
# 加载上层应用
|
||||
from vnpy.trader.app import riskManager#, ctaStrategy
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def main():
|
||||
"""主程序入口"""
|
||||
# 创建Qt应用对象
|
||||
qApp = createQApp()
|
||||
|
||||
# 创建事件引擎
|
||||
ee = EventEngine()
|
||||
|
||||
# 创建主引擎
|
||||
me = MainEngine(ee)
|
||||
|
||||
# 添加交易接口
|
||||
me.addGateway(futuGateway)
|
||||
|
||||
# 添加上层应用
|
||||
me.addApp(riskManager)
|
||||
#me.addApp(ctaStrategy)
|
||||
|
||||
# 创建主窗口
|
||||
mw = MainWindow(me, ee)
|
||||
mw.showMaximized()
|
||||
|
||||
# 在主线程中启动Qt事件循环
|
||||
sys.exit(qApp.exec_())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
BIN
examples/FutuTrader/temp/ContractData.vt.dat
Normal file
BIN
examples/FutuTrader/temp/ContractData.vt.dat
Normal file
Binary file not shown.
1
examples/FutuTrader/temp/ContractData.vt.dir
Normal file
1
examples/FutuTrader/temp/ContractData.vt.dir
Normal file
@ -0,0 +1 @@
|
||||
'data', (0, 1462865)
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"username": "请在quantos.org申请",
|
||||
"token": "请在quantos.org申请",
|
||||
"strategy": 625,
|
||||
"tradeAddress": "tcp://gw.quantos.org:8901",
|
||||
"dataAddress": "tcp://data.tushare.org:8910"
|
||||
}
|
@ -11,8 +11,9 @@ from time import sleep
|
||||
from datetime import datetime
|
||||
from copy import copy
|
||||
|
||||
import futuquant as ft
|
||||
from futuquant import (RET_ERROR, RET_OK, TrdEnv,
|
||||
from futuquant import (OpenQuoteContext, OpenHKTradeContext, OpenUSTradeContext,
|
||||
RET_ERROR, RET_OK,
|
||||
TrdEnv, TrdSide, OrderType, OrderStatus, ModifyOrderOp,
|
||||
StockQuoteHandlerBase, OrderBookHandlerBase,
|
||||
TradeOrderHandlerBase, TradeDealHandlerBase)
|
||||
|
||||
@ -33,23 +34,20 @@ productMap[PRODUCT_WARRANT] = 'WARRANT'
|
||||
productMap[PRODUCT_BOND] = 'BOND'
|
||||
|
||||
directionMap = {}
|
||||
directionMap[DIRECTION_LONG] = '0'
|
||||
directionMap[DIRECTION_SHORT] = '1'
|
||||
directionMap[DIRECTION_LONG] = TrdSide.BUY
|
||||
directionMap[DIRECTION_SHORT] = TrdSide.SELL
|
||||
directionMapReverse = {v:k for k,v in directionMap.items()}
|
||||
|
||||
statusMapReverse = {}
|
||||
statusMapReverse['0'] = STATUS_UNKNOWN
|
||||
statusMapReverse['1'] = STATUS_NOTTRADED
|
||||
statusMapReverse['2'] = STATUS_PARTTRADED
|
||||
statusMapReverse['3'] = STATUS_ALLTRADED
|
||||
statusMapReverse['4'] = STATUS_CANCELLED
|
||||
statusMapReverse['5'] = STATUS_REJECTED
|
||||
statusMapReverse['6'] = STATUS_CANCELLED
|
||||
statusMapReverse['7'] = STATUS_CANCELLED
|
||||
statusMapReverse['8'] = STATUS_UNKNOWN
|
||||
statusMapReverse['21'] = STATUS_UNKNOWN
|
||||
statusMapReverse['22'] = STATUS_UNKNOWN
|
||||
statusMapReverse['23'] = STATUS_UNKNOWN
|
||||
statusMapReverse[OrderStatus.NONE] = STATUS_UNKNOWN
|
||||
statusMapReverse[OrderStatus.SUBMITTED] = STATUS_NOTTRADED
|
||||
statusMapReverse[OrderStatus.FILLED_PART] = STATUS_PARTTRADED
|
||||
statusMapReverse[OrderStatus.FILLED_ALL] = STATUS_ALLTRADED
|
||||
statusMapReverse[OrderStatus.CANCELLED_ALL] = STATUS_CANCELLED
|
||||
statusMapReverse[OrderStatus.CANCELLED_PART] = STATUS_CANCELLED
|
||||
statusMapReverse[OrderStatus.SUBMIT_FAILED] = STATUS_REJECTED
|
||||
statusMapReverse[OrderStatus.FAILED] = STATUS_REJECTED
|
||||
statusMapReverse[OrderStatus.DISABLED] = STATUS_CANCELLED
|
||||
|
||||
|
||||
|
||||
@ -137,7 +135,7 @@ class FutuGateway(VtGateway):
|
||||
#----------------------------------------------------------------------
|
||||
def connectQuote(self):
|
||||
"""连接行情功能"""
|
||||
self.quoteCtx = ft.OpenQuoteContext(self.host, self.port)
|
||||
self.quoteCtx = OpenQuoteContext(self.host, self.port)
|
||||
|
||||
# 继承实现处理器类
|
||||
class QuoteHandler(StockQuoteHandlerBase):
|
||||
@ -176,9 +174,9 @@ class FutuGateway(VtGateway):
|
||||
"""连接交易功能"""
|
||||
# 连接交易接口
|
||||
if self.market == 'US':
|
||||
self.tradeCtx = ft.OpenUSTradeContext(self.host, self.port)
|
||||
self.tradeCtx = OpenUSTradeContext(self.host, self.port)
|
||||
else:
|
||||
self.tradeCtx = ft.OpenHKTradeContext(self.host, self.port)
|
||||
self.tradeCtx = OpenHKTradeContext(self.host, self.port)
|
||||
|
||||
# 继承实现处理器类
|
||||
class OrderHandler(TradeOrderHandlerBase):
|
||||
@ -204,7 +202,7 @@ class FutuGateway(VtGateway):
|
||||
return RET_OK, content
|
||||
|
||||
# 只有港股实盘交易才需要解锁
|
||||
if self.market == 'HK' and self.env == 0:
|
||||
if self.market == 'HK' and self.env == TrdEnv.REAL:
|
||||
self.tradeCtx.unlock_trade(self.password)
|
||||
|
||||
# 设置回调处理对象
|
||||
@ -229,26 +227,25 @@ class FutuGateway(VtGateway):
|
||||
def sendOrder(self, orderReq):
|
||||
"""发单"""
|
||||
side = directionMap[orderReq.direction]
|
||||
priceType = 0 # 只支持限价单
|
||||
priceType = OrderType.NORMAL # 只支持限价单
|
||||
|
||||
# 设置价格调整模式为向内调整(即买入调整后价格比原始价格低)
|
||||
if orderReq.direction == DIRECTION_LONG:
|
||||
priceMode = PriceRegularMode.LOWER
|
||||
adjustLimit = 0.05
|
||||
else:
|
||||
priceMode = PriceRegularMode.UPPER
|
||||
adjustLimit = -0.05
|
||||
|
||||
code, data = self.tradeCtx.place_order(orderReq.price, orderReq.volume,
|
||||
orderReq.symbol, side,
|
||||
priceType, self.env,
|
||||
order_deal_push=True,
|
||||
price_mode=priceMode)
|
||||
orderReq.symbol, side, priceType,
|
||||
trd_env=self.env,
|
||||
adjust_limit=adjustLimit)
|
||||
|
||||
if code:
|
||||
self.writeError(code, u'委托失败:%s' %data)
|
||||
return ''
|
||||
|
||||
for ix, row in data.iterrows():
|
||||
orderID = str(row['orderid'])
|
||||
orderID = str(row['order_id'])
|
||||
|
||||
vtOrderID = '.'.join([self.gatewayName, orderID])
|
||||
|
||||
@ -257,8 +254,8 @@ class FutuGateway(VtGateway):
|
||||
#----------------------------------------------------------------------
|
||||
def cancelOrder(self, cancelOrderReq):
|
||||
"""撤单"""
|
||||
code, data = self.tradeCtx.set_order_status(0, int(cancelOrderReq.orderID),
|
||||
self.env)
|
||||
code, data = self.tradeCtx.modify_order(ModifyOrderOp.CANCEL, cancelOrderReq.orderID,
|
||||
0, 0, trd_env=self.env)
|
||||
|
||||
if code:
|
||||
self.writeError(code, u'撤单失败:%s' %data)
|
||||
@ -304,9 +301,8 @@ class FutuGateway(VtGateway):
|
||||
|
||||
account.accountID = '%s_%s' %(self.gatewayName, self.market)
|
||||
account.vtAccountID = '.'.join([self.gatewayName, account.accountID])
|
||||
account.balance = float(row['ZCJZ'])
|
||||
account.margin = float(row['GPBZJ'])
|
||||
account.available = float(row['XJJY'])
|
||||
account.balance = float(row['total_assets'])
|
||||
account.available = float(row['avl_withdrawal_cash'])
|
||||
|
||||
self.onAccount(account)
|
||||
|
||||
@ -448,7 +444,7 @@ class FutuGateway(VtGateway):
|
||||
#----------------------------------------------------------------------
|
||||
def processOrderBook(self, data):
|
||||
"""订单簿推送"""
|
||||
symbol = data['stock_code']
|
||||
symbol = data['code']
|
||||
|
||||
tick = self.tickDict.get(symbol, None)
|
||||
if not tick:
|
||||
@ -487,25 +483,24 @@ class FutuGateway(VtGateway):
|
||||
order.symbol = row['code']
|
||||
order.vtSymbol = order.symbol
|
||||
|
||||
order.orderID = str(row['orderid'])
|
||||
order.orderID = str(row['order_id'])
|
||||
order.vtOrderID = '.'.join([self.gatewayName, order.orderID])
|
||||
|
||||
order.price = float(row['price'])
|
||||
order.totalVolume = int(row['qty'])
|
||||
order.tradedVolume = int(row['dealt_qty'])
|
||||
order.orderTime = row['create_time'].split(' ')[-1]
|
||||
|
||||
t = datetime.fromtimestamp(float(row['submited_time']))
|
||||
order.orderTime = t.strftime('%H:%M:%S')
|
||||
order.status = statusMapReverse.get(row['order_status'], STATUS_UNKNOWN)
|
||||
order.direction = directionMapReverse[row['trd_side']]
|
||||
|
||||
order.status = statusMapReverse.get(str(row['status']), STATUS_UNKNOWN)
|
||||
order.direction = directionMapReverse[str(row['order_side'])]
|
||||
self.onOrder(order)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def processDeal(self, data):
|
||||
"""处理成交推送"""
|
||||
for ix, row in data.iterrows():
|
||||
tradeID = row['dealid']
|
||||
tradeID = row['deal_id']
|
||||
if tradeID in self.tradeSet:
|
||||
continue
|
||||
self.tradeSet.add(tradeID)
|
||||
@ -519,14 +514,13 @@ class FutuGateway(VtGateway):
|
||||
trade.tradeID = tradeID
|
||||
trade.vtTradeID = '.'.join([self.gatewayName, trade.tradeID])
|
||||
|
||||
trade.orderID = row['orderid']
|
||||
trade.orderID = row['order_id']
|
||||
trade.vtOrderID = '.'.join([self.gatewayName, trade.orderID])
|
||||
|
||||
trade.price = float(row['price'])
|
||||
trade.volume = float(row['qty'])
|
||||
trade.direction = directionMapReverse[str(row['order_side'])]
|
||||
trade.direction = directionMapReverse[row['trd_side']]
|
||||
|
||||
t = datetime.fromtimestamp(float(row['time']))
|
||||
trade.tradeTime = t.strftime('%H:%M:%S')
|
||||
trade.tradeTime = row['create_time'].split(' ')[-1]
|
||||
|
||||
self.onTrade(trade)
|
Loading…
Reference in New Issue
Block a user