diff --git a/examples/FutuTrader/CTA_setting.json b/examples/FutuTrader/CTA_setting.json new file mode 100644 index 00000000..c1d08f4a --- /dev/null +++ b/examples/FutuTrader/CTA_setting.json @@ -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" + } +] \ No newline at end of file diff --git a/examples/FutuTrader/Futu_connect.json b/examples/FutuTrader/Futu_connect.json new file mode 100644 index 00000000..0d756707 --- /dev/null +++ b/examples/FutuTrader/Futu_connect.json @@ -0,0 +1,7 @@ +{ + "host": "127.0.0.1", + "port": 11111, + "market": "US", + "password": "123123", + "env": "REAL" +} \ No newline at end of file diff --git a/examples/FutuTrader/RM_setting.json b/examples/FutuTrader/RM_setting.json new file mode 100644 index 00000000..c22ac5fe --- /dev/null +++ b/examples/FutuTrader/RM_setting.json @@ -0,0 +1,10 @@ +{ + "active": false, + "orderFlowLimit": 50, + "orderFlowClear": 1, + "orderSizeLimit": 100, + "tradeLimit": 1000, + "workingOrderLimit": 20, + "orderCancelLimit": 10, + "marginRatioLimit": 0.85 +} \ No newline at end of file diff --git a/examples/FutuTrader/VT_setting.json b/examples/FutuTrader/VT_setting.json new file mode 100644 index 00000000..473017fb --- /dev/null +++ b/examples/FutuTrader/VT_setting.json @@ -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 +} \ No newline at end of file diff --git a/examples/FutuTrader/run.py b/examples/FutuTrader/run.py new file mode 100644 index 00000000..123cf5de --- /dev/null +++ b/examples/FutuTrader/run.py @@ -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() diff --git a/examples/FutuTrader/temp/ContractData.vt.dat b/examples/FutuTrader/temp/ContractData.vt.dat new file mode 100644 index 00000000..10634b68 Binary files /dev/null and b/examples/FutuTrader/temp/ContractData.vt.dat differ diff --git a/examples/FutuTrader/temp/ContractData.vt.dir b/examples/FutuTrader/temp/ContractData.vt.dir new file mode 100644 index 00000000..60f03216 --- /dev/null +++ b/examples/FutuTrader/temp/ContractData.vt.dir @@ -0,0 +1 @@ +'data', (0, 1462865) diff --git a/examples/VnTrader/TKPRO_connect.json b/examples/VnTrader/TKPRO_connect.json deleted file mode 100644 index 38b5a354..00000000 --- a/examples/VnTrader/TKPRO_connect.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "username": "请在quantos.org申请", - "token": "请在quantos.org申请", - "strategy": 625, - "tradeAddress": "tcp://gw.quantos.org:8901", - "dataAddress": "tcp://data.tushare.org:8910" -} \ No newline at end of file diff --git a/vnpy/trader/gateway/futuGateway/futuGateway.py b/vnpy/trader/gateway/futuGateway/futuGateway.py index f4a5431a..96aef1b9 100644 --- a/vnpy/trader/gateway/futuGateway/futuGateway.py +++ b/vnpy/trader/gateway/futuGateway/futuGateway.py @@ -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']) - - t = datetime.fromtimestamp(float(row['submited_time'])) - order.orderTime = t.strftime('%H:%M:%S') + order.orderTime = row['create_time'].split(' ')[-1] - order.status = statusMapReverse.get(str(row['status']), STATUS_UNKNOWN) - order.direction = directionMapReverse[str(row['order_side'])] + order.status = statusMapReverse.get(row['order_status'], STATUS_UNKNOWN) + order.direction = directionMapReverse[row['trd_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) \ No newline at end of file