diff --git a/README-en.md b/README-en.md index fdd3993f..c0325751 100644 --- a/README-en.md +++ b/README-en.md @@ -16,8 +16,6 @@ Using the vn.py project, institutional investors and professional traders, such **International Financial Markets** - Interactive Brokers(vn.ib) - - - OANDA(vn.oanda) - Shanghai Zhida Futures(vn.shzd) diff --git a/README.md b/README.md index 85cb7be9..0aff9bce 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,6 @@ vn.py是基于Python的开源量化交易程序开发框架,起源于国内私 - Interactive Brokers(ib) - - OANDA(oanda) - - 福汇(fxcm) - OKCOIN(okcoin) @@ -125,14 +123,8 @@ sudo /home/vnpy/anaconda2/bin/conda install -c quantopian ta-lib=0.4.9 ``` # encoding: UTF-8 -# 重载sys模块,设置默认字符串编码方式为utf8 import sys reload(sys) -sys.setdefaultencoding('utf8') - -# 判断操作系统 -import platform -system = platform.system() # vn.trader模块 from vnpy.event import EventEngine @@ -141,18 +133,11 @@ from vnpy.trader.uiQt import createQApp from vnpy.trader.uiMainWindow import MainWindow # 加载底层接口 -from vnpy.trader.gateway import (ctpGateway, oandaGateway, ibGateway, - tkproGateway) - -if system == 'Windows': - from vnpy.trader.gateway import (femasGateway, xspeedGateway, - futuGateway, secGateway) - -if system == 'Linux': - from vnpy.trader.gateway import xtpGateway +from vnpy.trader.gateway import ctpGateway, ibGateway # 加载上层应用 -from vnpy.trader.app import (riskManager, ctaStrategy, spreadTrading) +from vnpy.trader.app import (riskManager, ctaStrategy, + spreadTrading, algoTrading) #---------------------------------------------------------------------- @@ -160,37 +145,27 @@ def main(): """主程序入口""" # 创建Qt应用对象 qApp = createQApp() - + # 创建事件引擎 ee = EventEngine() - + # 创建主引擎 me = MainEngine(ee) - + # 添加交易接口 me.addGateway(ctpGateway) - me.addGateway(tkproGateway) - me.addGateway(oandaGateway) me.addGateway(ibGateway) - - if system == 'Windows': - me.addGateway(femasGateway) - me.addGateway(xspeedGateway) - me.addGateway(secGateway) - me.addGateway(futuGateway) - - if system == 'Linux': - me.addGateway(xtpGateway) - + # 添加上层应用 me.addApp(riskManager) me.addApp(ctaStrategy) me.addApp(spreadTrading) - + me.addApp(algoTrading) + # 创建主窗口 mw = MainWindow(me, ee) mw.showMaximized() - + # 在主线程中启动Qt事件循环 sys.exit(qApp.exec_()) diff --git a/examples/VnTrader/OANDA_connect.json b/examples/VnTrader/OANDA_connect.json deleted file mode 100644 index 21dd2cd9..00000000 --- a/examples/VnTrader/OANDA_connect.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "token": "请在OANDA网站申请", - "accountId": "请在OANDA网站申请", - "settingName": "practice" -} \ No newline at end of file diff --git a/examples/VnTrader/run.py b/examples/VnTrader/run.py index 9eaf85d3..b2975c27 100644 --- a/examples/VnTrader/run.py +++ b/examples/VnTrader/run.py @@ -5,9 +5,14 @@ try: reload # Python 2 except NameError: # Python 3 from importlib import reload + import sys reload(sys) -sys.setdefaultencoding('utf8') + +try: + sys.setdefaultencoding('utf8') +except AttributeError: + pass # 判断操作系统 import platform @@ -20,8 +25,7 @@ from vnpy.trader.uiQt import createQApp from vnpy.trader.uiMainWindow import MainWindow # 加载底层接口 -from vnpy.trader.gateway import (ctpGateway, oandaGateway, - ibGateway) +from vnpy.trader.gateway import (ctpGateway, ibGateway) if system == 'Linux': from vnpy.trader.gateway import xtpGateway @@ -48,7 +52,6 @@ def main(): # 添加交易接口 me.addGateway(ctpGateway) - me.addGateway(oandaGateway) me.addGateway(ibGateway) if system == 'Windows': diff --git a/vnpy/api/README.md b/vnpy/api/README.md index 539dceee..442d81f7 100644 --- a/vnpy/api/README.md +++ b/vnpy/api/README.md @@ -12,7 +12,6 @@ ### 外盘 * vn.ib:Interactive Brokers接口 -* vn.oanda:OANDA接口 * vn.shzd:直达期货接口 ### 比特币 diff --git a/vnpy/api/oanda/README.md b/vnpy/api/oanda/README.md deleted file mode 100644 index 01522ddd..00000000 --- a/vnpy/api/oanda/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# vn.oanda - -### 简介 -OANDA外汇交易接口,基于REST API开发,实现了以下功能: - -1. 发送、修改、撤销委托 - -2. 查询委托、持仓(按照每笔成交算)、汇总持仓(按照单一货币对算)、资金、成交历史 - -3. 实时行情和成交推送 - -4. 获取Forex Lab中的日历、订单簿、历史持仓比、价差、交易商持仓、Autochartist - -目前该API尚处于测试阶段,如果发现bug或者需要改进的地方请在github上开issue给我。 - -### 特点 -相比较于[OANDA官网](http://developer.oanda.com/rest-live/sample-code/)上贴出的一些Python API(如pyoanda、oanda-trading-environment等),vn.oanda的一些不同: - -1. 面向对象的API设计,接近CTP API的结构,对于国内用户而言更容易上手 - -2. 三个独立的工作线程,分别处理:用户请求(如发送委托等)、行情推送、事件推送(如成交事件等),提供更高的性能 - -3. 参考CTP API的设计,主动函数调用的结果通过异步(回调函数)的方式推送到程序中,适用于开发真正可靠的实盘交易程序(pyoanda里使用的同步阻塞工作模式在实盘应用中的风险:想象你的交易程序发送委托请求后,因为网络问题不能立即返回,因此主线程阻塞导致界面卡死或者背后的策略引擎线程卡死,对新的行情事件完全失去响应) - -### Quick Start -1. 安装Anaconda 2.7 32位 - -2. 前往[OANDA](http://www.oanda.com)注册一个fxTrade practice测试账户(注意国家不要选中国,会无法申请API token,作者测试英国可以) - -3. 在网站登陆后,进入Manage Funds,记录下自己的Account Number - -4. 回到上一个界面,左侧有个Manage API Access(在Recent Logins上方,没有的就是第一步国家选错了),进入后生成token - -5. 下载vn.oanda到本地后,打开test.py,修改token和accountId为你的信息 - -6. 将test.py中想要测试的功能取消注释,开始使用吧! - -### API版本 -日期:2016-02-27 - -链接:[http://developer.oanda.com/rest-live/introduction/](http://developer.oanda.com/rest-live/introduction/) - diff --git a/vnpy/api/oanda/__init__.py b/vnpy/api/oanda/__init__.py deleted file mode 100644 index 68530d94..00000000 --- a/vnpy/api/oanda/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# encoding: UTF-8 - -from __future__ import absolute_import -from .vnoanda import OandaApi \ No newline at end of file diff --git a/vnpy/api/oanda/test.py b/vnpy/api/oanda/test.py deleted file mode 100644 index 11e721c4..00000000 --- a/vnpy/api/oanda/test.py +++ /dev/null @@ -1,106 +0,0 @@ -# encoding: utf-8 - -from __future__ import absolute_import -from .vnoanda import OandaApi - - -if __name__ == '__main__': - token = '' - accountId = '' - - api = OandaApi() - api.DEBUG = True - - api.init('practice', token, accountId) - - # 获取交易合约列表,通过 - #api.getInstruments({'accountId': accountId}) - - # 获取价格,通过 - #api.getPrices({'instruments': 'EUR_USD'}) - - # 获取历史数据,失败 - #api.getPriceHisory({'instrument': 'EUR_USD', - #'granularity': 'D', - #'candleFormat': 'midpoint', - #'count': '50'}) - - # 查询用户的所有账户,通过 - #api.getAccounts() - - # 查询账户信息,通过 - #api.getAccountInfo() - - # 查询委托数据,通过 - #api.getOrders({}) - - # 发送委托,通过 - #api.sendOrder({'instrument': 'EUR_USD', - #'units': '10000', - #'side': 'buy', - #'type': 'market'}) - - # 查询委托数据,通过 - #api.getOrderInfo('123') - - # 修改委托,通过 - #api.modifyOrder({'units': '10000', - #'side': 'buy', - #'type': 'market'}, '123') - - # 撤销委托,通过 - #api.cancelOrder('123') - - # 查询所有持仓,通过 - #api.getTrades({}) - - # 查询持仓数据,通过 - #api.getTradeInfo('10125150909') - - # 修改持仓,通过 - #api.modifyTrade({'trailingStop': '150'}, '10125150909') - - # 平仓,通过 - #api.closeTrade('10125150909') - - # 查询汇总持仓,通过 - #api.getPositions() - - # 查询汇总持仓细节,通过 - #api.getPositionInfo('EUR_USD') - - # 平仓汇总持仓,通过 - #api.closePosition('EUR_USD') - - # 查询账户资金变动,通过 - #api.getTransactions({}) - - # 查询资金变动信息,通过 - #api.getTransactionInfo('10135713982') - - # 查询账户变动历史,部分通过,某些情况下可能触发JSONDecodeError - #api.getAccountHistory() - - # 查询财经日历,通过 - #api.getCalendar({'period': '604800'}) - - # 查询历史持仓比,通过 - #api.getPositionRatios({'instrument': 'EUR_USD', - #'period': '604800'}) - - # 查询历史价差,通过 - #api.getSpreads({'instrument': 'EUR_USD', - #'period': '604800'}) - - # 查询交易商持仓,通过 - #api.getCommitments({'instrument': 'EUR_USD'}) - - # 查询订单簿,通过 - #api.getOrderbook({'instrument': 'EUR_USD', - #'period': '604800'}) - - # 查询Autochartist,失败,OANDA服务器报错 - #api.getAutochartist({'instrument': 'EUR_USD'}) - - # 阻塞 - input() diff --git a/vnpy/api/oanda/vnoanda.py b/vnpy/api/oanda/vnoanda.py deleted file mode 100644 index 2f5f63fb..00000000 --- a/vnpy/api/oanda/vnoanda.py +++ /dev/null @@ -1,610 +0,0 @@ -# encoding: utf-8 - -from __future__ import print_function -import json -import requests -from Queue import Queue, Empty -from threading import Thread - - -API_SETTING = {} -API_SETTING['practice'] = {'rest': 'https://api-fxpractice.oanda.com', - 'stream': 'https://stream-fxpractice.oanda.com'} -API_SETTING['trade'] = {'rest': 'https://api-fxtrade.oanda.com', - 'stream': 'https://stream-fxtrade.oanda.com'} - - -FUNCTIONCODE_GETINSTRUMENTS = 0 -FUNCTIONCODE_GETPRICES = 1 -FUNCTIONCODE_GETPRICEHISTORY = 2 -FUNCTIONCODE_GETACCOUNTS = 3 -FUNCTIONCODE_GETACCOUNTINFO = 4 -FUNCTIONCODE_GETORDERS = 5 -FUNCTIONCODE_SENDORDER = 6 -FUNCTIONCODE_GETORDERINFO = 7 -FUNCTIONCODE_MODIFYORDER = 8 -FUNCTIONCODE_CANCELORDER = 9 -FUNCTIONCODE_GETTRADES = 10 -FUNCTIONCODE_GETTRADEINFO = 11 -FUNCTIONCODE_MODIFYTRADE= 12 -FUNCTIONCODE_CLOSETRADE = 13 -FUNCTIONCODE_GETPOSITIONS = 14 -FUNCTIONCODE_GETPOSITIONINFO= 15 -FUNCTIONCODE_CLOSEPOSITION = 16 -FUNCTIONCODE_GETTRANSACTIONS = 17 -FUNCTIONCODE_GETTRANSACTIONINFO = 18 -FUNCTIONCODE_GETACCOUNTHISTORY = 19 -FUNCTIONCODE_GETCALENDAR = 20 -FUNCTIONCODE_GETPOSITIONRATIOS = 21 -FUNCTIONCODE_GETSPREADS = 22 -FUNCTIONCODE_GETCOMMIMENTS = 23 -FUNCTIONCODE_GETORDERBOOK = 24 -FUNCTIONCODE_GETAUTOCHARTIST = 25 -FUNCTIONCODE_STREAMPRICES = 26 -FUNCTIONCODE_STREAMEVENTS = 27 - - -######################################################################## -class OandaApi(object): - """""" - DEBUG = False - - #---------------------------------------------------------------------- - def __init__(self): - """Constructor""" - self.token = '' - self.accountId = '' - self.headers = {} - self.restDomain = '' - self.streamDomain = '' - self.session = None - - self.functionSetting = {} - - self.active = False # API的工作状态 - - self.reqID = 0 # 请求编号 - self.reqQueue = Queue() # 请求队列 - self.reqThread = Thread(target=self.processQueue) # 请求处理线程 - - self.streamPricesThread = Thread(target=self.processStreamPrices) # 实时行情线程 - self.streamEventsThread = Thread(target=self.processStreamEvents) # 实时事件线程(成交等) - - #---------------------------------------------------------------------- - def init(self, settingName, token, accountId): - """初始化接口""" - self.restDomain = API_SETTING[settingName]['rest'] - self.streamDomain = API_SETTING[settingName]['stream'] - self.session = requests.Session() - - self.token = token - self.accountId = accountId - - self.headers['Authorization'] = 'Bearer ' + self.token - - self.initFunctionSetting(FUNCTIONCODE_GETINSTRUMENTS, {'path': '/v1/instruments', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETPRICES, {'path': '/v1/prices', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETPRICEHISTORY, {'path': '/v1/candles', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETACCOUNTS, {'path': '/v1/accounts', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETACCOUNTINFO, {'path': '/v1/accounts/%s' %self.accountId, - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETORDERS, {'path': '/v1/accounts/%s/orders' %self.accountId, - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_SENDORDER, {'path': '/v1/accounts/%s/orders' %self.accountId, - 'method': 'POST'}) - - self.initFunctionSetting(FUNCTIONCODE_GETORDERINFO, {'path': '/v1/accounts/%s/orders' %self.accountId, - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_MODIFYORDER, {'path': '/v1/accounts/%s/orders' %self.accountId, - 'method': 'PATCH'}) - - self.initFunctionSetting(FUNCTIONCODE_CANCELORDER, {'path': '/v1/accounts/%s/orders' %self.accountId, - 'method': 'DELETE'}) - - self.initFunctionSetting(FUNCTIONCODE_GETTRADES, {'path': '/v1/accounts/%s/trades' %self.accountId, - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETTRADEINFO, {'path': '/v1/accounts/%s/trades' %self.accountId, - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_MODIFYTRADE, {'path': '/v1/accounts/%s/trades' %self.accountId, - 'method': 'PATCH'}) - - self.initFunctionSetting(FUNCTIONCODE_CLOSETRADE, {'path': '/v1/accounts/%s/trades' %self.accountId, - 'method': 'DELETE'}) - - self.initFunctionSetting(FUNCTIONCODE_GETPOSITIONS, {'path': '/v1/accounts/%s/positions' %self.accountId, - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETPOSITIONINFO, {'path': '/v1/accounts/%s/positions' %self.accountId, - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_CLOSEPOSITION, {'path': '/v1/accounts/%s/positions' %self.accountId, - 'method': 'DELETE'}) - - self.initFunctionSetting(FUNCTIONCODE_GETTRANSACTIONS, {'path': '/v1/accounts/%s/transactions' %self.accountId, - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETTRANSACTIONINFO, {'path': '/v1/accounts/%s/transactions' %self.accountId, - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETACCOUNTHISTORY, {'path': '/v1/accounts/%s/alltransactions' %self.accountId, - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETCALENDAR, {'path': '/labs/v1/calendar', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETPOSITIONRATIOS, {'path': '/labs/v1/historical_position_ratios', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETSPREADS, {'path': '/labs/v1/spreads', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETCOMMIMENTS, {'path': '/labs/v1/commitments', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETORDERBOOK, {'path': '/labs/v1/orderbook_data', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETAUTOCHARTIST, {'path': '/labs/v1/autochartist', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_GETAUTOCHARTIST, {'path': '/labs/v1/autochartist', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_STREAMPRICES, {'path': '/v1/prices', - 'method': 'GET'}) - - self.initFunctionSetting(FUNCTIONCODE_STREAMEVENTS, {'path': '/v1/events', - 'method': 'GET'}) - - - self.active = True - self.reqThread.start() - self.streamEventsThread.start() - self.streamPricesThread.start() - - #---------------------------------------------------------------------- - def exit(self): - """退出接口""" - if self.active: - self.active = False - self.reqThread.join() - - #---------------------------------------------------------------------- - def initFunctionSetting(self, code, setting): - """初始化API功能字典""" - self.functionSetting[code] = setting - - #---------------------------------------------------------------------- - def processRequest(self, req): - """发送请求并通过回调函数推送数据结果""" - url = req['url'] - method = req['method'] - params = req['params'] - - stream = False - if 'stream' in req: - stream = req['stream'] - - if method in ['GET', 'DELETE']: - myreq = requests.Request(method, url, headers=self.headers, params=params) - elif method in ['POST', 'PATCH']: - myreq = requests.Request(method, url, headers=self.headers, data=params) - pre = myreq.prepare() - - r = None - error = None - - try: - r = self.session.send(pre, stream=stream) - except Exception as e: - error = e - - return r, error - - #---------------------------------------------------------------------- - def processQueue(self): - """处理请求队列中的请求""" - while self.active: - try: - req = self.reqQueue.get(block=True, timeout=1) # 获取请求的阻塞为一秒 - callback = req['callback'] - reqID = req['reqID'] - - r, error = self.processRequest(req) - - if r: - try: - data = r.json() - if self.DEBUG: - print(callback.__name__) - callback(data, reqID) - except Exception as e: - self.onError(str(e), reqID) - else: - self.onError(error, reqID) - except Empty: - pass - - #---------------------------------------------------------------------- - def sendRequest(self, code, params, callback, optional=''): - """发送请求""" - setting = self.functionSetting[code] - - url = self.restDomain + setting['path'] - if optional: - url = url + '/' + optional - - self.reqID += 1 - - req = {'url': url, - 'method': setting['method'], - 'params': params, - 'callback': callback, - 'reqID': self.reqID} - self.reqQueue.put(req) - - return self.reqID - - #---------------------------------------------------------------------- - def onError(self, error, reqID): - """错误信息回调""" - print(error, reqID) - - #---------------------------------------------------------------------- - def getInstruments(self, params): - """查询可交易的合约列表""" - return self.sendRequest(FUNCTIONCODE_GETINSTRUMENTS, params, self.onGetInstruments) - - #---------------------------------------------------------------------- - def onGetInstruments(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getPrices(self, params): - """查询价格""" - return self.sendRequest(FUNCTIONCODE_GETPRICES, params, self.onGetPrices) - - #---------------------------------------------------------------------- - def onGetPrices(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getPriceHisory(self, params): - """查询历史价格数据""" - return self.sendRequest(FUNCTIONCODE_GETPRICEHISTORY, params, self.onGetPriceHistory) - - #---------------------------------------------------------------------- - def onGetPriceHistory(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getAccounts(self): - """查询用户的所有账户""" - return self.sendRequest(FUNCTIONCODE_GETACCOUNTS, {}, self.onGetAccounts) - - #---------------------------------------------------------------------- - def onGetAccounts(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getAccountInfo(self): - """查询账户数据""" - return self.sendRequest(FUNCTIONCODE_GETACCOUNTINFO, {}, self.onGetAccountInfo) - - #---------------------------------------------------------------------- - def onGetAccountInfo(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getOrders(self, params): - """查询所有委托""" - return self.sendRequest(FUNCTIONCODE_GETORDERS, params, self.onGetOrders) - - #---------------------------------------------------------------------- - def onGetOrders(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def sendOrder(self, params): - """发送委托""" - return self.sendRequest(FUNCTIONCODE_SENDORDER, params, self.onSendOrder) - - #---------------------------------------------------------------------- - def onSendOrder(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getOrderInfo(self, optional): - """查询委托信息""" - return self.sendRequest(FUNCTIONCODE_GETORDERINFO, {}, self.onGetOrderInfo, optional) - - #---------------------------------------------------------------------- - def onGetOrderInfo(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def modifyOrder(self, params, optional): - """修改委托""" - return self.sendRequest(FUNCTIONCODE_MODIFYORDER, params, self.onModifyOrder, optional) - - #---------------------------------------------------------------------- - def onModifyOrder(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def cancelOrder(self, optional): - """查询委托信息""" - return self.sendRequest(FUNCTIONCODE_CANCELORDER, {}, self.onCancelOrder, optional) - - #---------------------------------------------------------------------- - def onCancelOrder(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getTrades(self, params): - """查询所有仓位""" - return self.sendRequest(FUNCTIONCODE_GETTRADES, params, self.onGetTrades) - - #---------------------------------------------------------------------- - def onGetTrades(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getTradeInfo(self, optional): - """查询仓位信息""" - return self.sendRequest(FUNCTIONCODE_GETTRADEINFO, {}, self.onGetTradeInfo, optional) - - #---------------------------------------------------------------------- - def onGetTradeInfo(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def modifyTrade(self, params, optional): - """修改仓位""" - return self.sendRequest(FUNCTIONCODE_MODIFYTRADE, params, self.onModifyTrade, optional) - - #---------------------------------------------------------------------- - def onModifyTrade(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def closeTrade(self, optional): - """平仓""" - return self.sendRequest(FUNCTIONCODE_CLOSETRADE, {}, self.onCloseTrade, optional) - - #---------------------------------------------------------------------- - def onCloseTrade(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getPositions(self): - """查询所有汇总仓位""" - return self.sendRequest(FUNCTIONCODE_GETPOSITIONS, {}, self.onGetPositions) - - #---------------------------------------------------------------------- - def onGetPositions(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getPositionInfo(self, optional): - """查询汇总仓位信息""" - return self.sendRequest(FUNCTIONCODE_GETPOSITIONINFO, {}, self.onGetPositionInfo, optional) - - #---------------------------------------------------------------------- - def onGetPositionInfo(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def closePosition(self, optional): - """平仓汇总仓位信息""" - return self.sendRequest(FUNCTIONCODE_CLOSEPOSITION, {}, self.onClosePosition, optional) - - #---------------------------------------------------------------------- - def onClosePosition(self, data, reqID): - """回调函数""" - print(data, reqID) - - - #---------------------------------------------------------------------- - def getTransactions(self, params): - """查询所有资金变动""" - return self.sendRequest(FUNCTIONCODE_GETTRANSACTIONS, params, self.onGetTransactions) - - #---------------------------------------------------------------------- - def onGetTransactions(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getTransactionInfo(self, optional): - """查询资金变动信息""" - return self.sendRequest(FUNCTIONCODE_GETTRANSACTIONINFO, {}, self.onGetTransactionInfo, optional) - - #---------------------------------------------------------------------- - def onGetTransactionInfo(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getAccountHistory(self): - """查询账户资金变动历史""" - return self.sendRequest(FUNCTIONCODE_GETACCOUNTHISTORY, {}, self.onGetAccountHistory) - - #---------------------------------------------------------------------- - def onGetAccountHistory(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getCalendar(self, params): - """查询日历""" - return self.sendRequest(FUNCTIONCODE_GETCALENDAR, params, self.onGetCalendar) - - #---------------------------------------------------------------------- - def onGetCalendar(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getPositionRatios(self, params): - """查询持仓比例""" - return self.sendRequest(FUNCTIONCODE_GETPOSITIONRATIOS, params, self.onGetPositionRatios) - - #---------------------------------------------------------------------- - def onGetPositionRatios(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getSpreads(self, params): - """查询所有仓位""" - return self.sendRequest(FUNCTIONCODE_GETSPREADS, params, self.onGetSpreads) - - #---------------------------------------------------------------------- - def onGetSpreads(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getCommitments(self, params): - """查询交易商持仓情况""" - return self.sendRequest(FUNCTIONCODE_GETCOMMIMENTS, params, self.onGetCommitments) - - #---------------------------------------------------------------------- - def onGetCommitments(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getOrderbook(self, params): - """查询订单簿""" - return self.sendRequest(FUNCTIONCODE_GETORDERBOOK, params, self.onGetOrderbook) - - #---------------------------------------------------------------------- - def onGetOrderbook(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def getAutochartist(self, params): - """查询Autochartist识别的模式""" - return self.sendRequest(FUNCTIONCODE_GETAUTOCHARTIST, params, self.onGetAutochartist) - - #---------------------------------------------------------------------- - def onGetAutochartist(self, data, reqID): - """回调函数""" - print(data, reqID) - - #---------------------------------------------------------------------- - def onPrice(self, data): - """行情推送""" - print(data) - - #---------------------------------------------------------------------- - def onEvent(self, data): - """事件推送(成交等)""" - print(data) - - #---------------------------------------------------------------------- - def processStreamPrices(self): - """获取价格推送""" - # 首先获取所有合约的代码 - setting = self.functionSetting[FUNCTIONCODE_GETINSTRUMENTS] - req = {'url': self.restDomain + setting['path'], - 'method': setting['method'], - 'params': {'accountId': self.accountId}} - r, error = self.processRequest(req) - if r: - try: - data = r.json() - symbols = [d['instrument'] for d in data['instruments']] - except Exception as e: - self.onError(e, -1) - return - else: - self.onError(error, -1) - return - - # 然后订阅所有的合约行情 - setting = self.functionSetting[FUNCTIONCODE_STREAMPRICES] - params = {'accountId': self.accountId, - 'instruments': ','.join(symbols)} - req = {'url': self.streamDomain + setting['path'], - 'method': setting['method'], - 'params': params, - 'stream': True} - r, error = self.processRequest(req) - - if r: - for line in r.iter_lines(): - if line: - try: - msg = json.loads(line) - - if self.DEBUG: - print(self.onPrice.__name__) - - self.onPrice(msg) - except Exception as e: - self.onError(e, -1) - - if not self.active: - break - else: - self.onError(error, -1) - - #---------------------------------------------------------------------- - def processStreamEvents(self): - """获取事件推送""" - setting = self.functionSetting[FUNCTIONCODE_STREAMEVENTS] - req = {'url': self.streamDomain + setting['path'], - 'method': setting['method'], - 'params': {}, - 'stream': True} - r, error = self.processRequest(req) - if r: - for line in r.iter_lines(): - if line: - try: - msg = json.loads(line) - - if self.DEBUG: - print(self.onEvent.__name__) - - self.onEvent(msg) - except Exception as e: - self.onError(e, -1) - - if not self.active: - break - else: - self.onError(error, -1) diff --git a/vnpy/trader/gateway/fxcmGateway/fxcmGateway.py b/vnpy/trader/gateway/fxcmGateway/fxcmGateway.py index fc5f323f..f0345dd6 100644 --- a/vnpy/trader/gateway/fxcmGateway/fxcmGateway.py +++ b/vnpy/trader/gateway/fxcmGateway/fxcmGateway.py @@ -554,7 +554,7 @@ class Api(FxcmApi): #---------------------------------------------------------------------- def getTime(s): - """把OANDA返回的时间格式转化为简单的时间字符串""" + """把时间格式转化为简单的时间字符串""" month = s[:2] day = s[2:4] year = s[4:8] diff --git a/vnpy/trader/gateway/oandaGateway/OANDA_connect.json b/vnpy/trader/gateway/oandaGateway/OANDA_connect.json deleted file mode 100644 index 21dd2cd9..00000000 --- a/vnpy/trader/gateway/oandaGateway/OANDA_connect.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "token": "请在OANDA网站申请", - "accountId": "请在OANDA网站申请", - "settingName": "practice" -} \ No newline at end of file diff --git a/vnpy/trader/gateway/oandaGateway/__init__.py b/vnpy/trader/gateway/oandaGateway/__init__.py deleted file mode 100644 index 7ba3dbdb..00000000 --- a/vnpy/trader/gateway/oandaGateway/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# encoding: UTF-8 - -from __future__ import absolute_import -from vnpy.trader import vtConstant -from .oandaGateway import OandaGateway - -gatewayClass = OandaGateway -gatewayName = 'OANDA' -gatewayDisplayName = gatewayName -gatewayType = vtConstant.GATEWAYTYPE_INTERNATIONAL -gatewayQryEnabled = True diff --git a/vnpy/trader/gateway/oandaGateway/oandaGateway.py b/vnpy/trader/gateway/oandaGateway/oandaGateway.py deleted file mode 100644 index 9623f29d..00000000 --- a/vnpy/trader/gateway/oandaGateway/oandaGateway.py +++ /dev/null @@ -1,458 +0,0 @@ -# encoding: UTF-8 - -''' -vn.oanda的gateway接入 - -由于OANDA采用的是外汇做市商的交易模式,因此和国内接口方面有若干区别,具体如下: - -* 行情数据反映的是OANDA的报价变化,因此只有买卖价,而没有成交价 - -* OANDA的持仓管理分为单笔成交持仓(Trade数据,国内没有) - 和单一资产汇总持仓(Position数据) - -* OANDA系统中的所有时间都采用UTC时间(世界协调时,中国是UTC+8) - -* 由于采用的是外汇做市商的模式,用户的限价委托当价格被触及时就会立即全部成交, - 不会出现部分成交的情况,因此委托状态只有已报、成交、撤销三种 - -* 外汇市场采用24小时交易,因此OANDA的委托不像国内收盘后自动失效,需要用户指定 - 失效时间,本接口中默认设置为24个小时候失效 -''' - - -import os -import json -import datetime - -from vnpy.api.oanda import OandaApi -from vnpy.trader.vtGateway import * -from vnpy.trader.vtFunction import getJsonPath - -# 价格类型映射 -priceTypeMap = {} -priceTypeMap[PRICETYPE_LIMITPRICE] = 'limit' -priceTypeMap[PRICETYPE_MARKETPRICE] = 'market' -priceTypeMapReverse = {v: k for k, v in priceTypeMap.items()} - -# 方向类型映射 -directionMap = {} -directionMap[DIRECTION_LONG] = 'buy' -directionMap[DIRECTION_SHORT] = 'sell' -directionMapReverse = {v: k for k, v in directionMap.items()} - - -######################################################################## -class OandaGateway(VtGateway): - """OANDA接口""" - - #---------------------------------------------------------------------- - def __init__(self, eventEngine, gatewayName='OANDA'): - """Constructor""" - super(OandaGateway, self).__init__(eventEngine, gatewayName) - - self.api = Api(self) - - self.qryEnabled = False # 是否要启动循环查询 - - self.fileName = self.gatewayName + '_connect.json' - self.filePath = getJsonPath(self.fileName, __file__) - - #---------------------------------------------------------------------- - def connect(self): - """连接""" - # 载入json文件 - try: - f = file(self.filePath) - except IOError: - log = VtLogData() - log.gatewayName = self.gatewayName - log.logContent = u'读取连接配置出错,请检查' - self.onLog(log) - return - - # 解析json文件 - setting = json.load(f) - try: - token = str(setting['token']) - accountId = str(setting['accountId']) - settingName = str(setting['settingName']) - except KeyError: - log = VtLogData() - log.gatewayName = self.gatewayName - log.logContent = u'连接配置缺少字段,请检查' - self.onLog(log) - return - - # 初始化接口 - self.api.init(settingName, token, accountId) - log = VtLogData() - log.gatewayName = self.gatewayName - log.logContent = u'接口初始化成功' - self.onLog(log) - - # 查询信息 - self.api.qryInstruments() - self.api.qryOrders() - self.api.qryTrades() - - # 初始化并启动查询 - self.initQuery() - - #---------------------------------------------------------------------- - def subscribe(self, subscribeReq): - """订阅行情""" - pass - - #---------------------------------------------------------------------- - def sendOrder(self, orderReq): - """发单""" - return self.api.sendOrder_(orderReq) - - #---------------------------------------------------------------------- - def cancelOrder(self, cancelOrderReq): - """撤单""" - self.api.cancelOrder_(cancelOrderReq) - - #---------------------------------------------------------------------- - def qryAccount(self): - """查询账户资金""" - self.api.getAccountInfo() - - #---------------------------------------------------------------------- - def qryPosition(self): - """查询持仓""" - self.api.getPositions() - - #---------------------------------------------------------------------- - def close(self): - """关闭""" - self.api.exit() - - #---------------------------------------------------------------------- - def initQuery(self): - """初始化连续查询""" - if self.qryEnabled: - # 需要循环的查询函数列表 - self.qryFunctionList = [self.qryAccount, self.qryPosition] - - self.qryCount = 0 # 查询触发倒计时 - self.qryTrigger = 2 # 查询触发点 - self.qryNextFunction = 0 # 上次运行的查询函数索引 - - self.startQuery() - - #---------------------------------------------------------------------- - def query(self, event): - """注册到事件处理引擎上的查询函数""" - self.qryCount += 1 - - if self.qryCount > self.qryTrigger: - # 清空倒计时 - self.qryCount = 0 - - # 执行查询函数 - function = self.qryFunctionList[self.qryNextFunction] - function() - - # 计算下次查询函数的索引,如果超过了列表长度,则重新设为0 - self.qryNextFunction += 1 - if self.qryNextFunction == len(self.qryFunctionList): - self.qryNextFunction = 0 - - #---------------------------------------------------------------------- - def startQuery(self): - """启动连续查询""" - self.eventEngine.register(EVENT_TIMER, self.query) - - #---------------------------------------------------------------------- - def setQryEnabled(self, qryEnabled): - """设置是否要启动循环查询""" - self.qryEnabled = qryEnabled - - - -######################################################################## -class Api(OandaApi): - """OANDA的API实现""" - - #---------------------------------------------------------------------- - def __init__(self, gateway): - """Constructor""" - super(Api, self).__init__() - - self.gateway = gateway # gateway对象 - self.gatewayName = gateway.gatewayName # gateway对象名称 - - self.orderDict = {} # 缓存委托数据 - - #---------------------------------------------------------------------- - def onError(self, error, reqID): - """错误信息回调""" - err = VtErrorData() - err.gatewayName = self.gatewayName - err.errorMsg = error - self.gateway.onError(err) - - #---------------------------------------------------------------------- - def onGetInstruments(self, data, reqID): - """回调函数""" - if not 'instruments' in data: - return - l = data['instruments'] - for d in l: - contract = VtContractData() - contract.gatewayName = self.gatewayName - - contract.symbol = d['instrument'] - contract.name = d['displayName'] - contract.exchange = EXCHANGE_OANDA - contract.vtSymbol = '.'.join([contract.symbol, contract.exchange]) - contract.priceTick = float(d['pip']) - contract.size = 1 - contract.productClass = PRODUCT_FOREX - self.gateway.onContract(contract) - - self.writeLog(u'交易合约信息查询完成') - - #---------------------------------------------------------------------- - def onGetAccountInfo(self, data, reqID): - """回调函数""" - account = VtAccountData() - account.gatewayName = self.gatewayName - - account.accountID = str(data['accountId']) - account.vtAccountID = '.'.join([self.gatewayName, account.accountID]) - - account.available = data['marginAvail'] - account.margin = data['marginUsed'] - account.closeProfit = data['realizedPl'] - account.positionProfit = data['unrealizedPl'] - account.balance = data['balance'] - - self.gateway.onAccount(account) - - #---------------------------------------------------------------------- - def onGetOrders(self, data, reqID): - """回调函数""" - if not 'orders' in data: - return - l = data['orders'] - - for d in l: - order = VtOrderData() - order.gatewayName = self.gatewayName - - order.symbol = d['instrument'] - order.exchange = EXCHANGE_OANDA - order.vtSymbol = '.'.join([order.symbol, order.exchange]) - order.orderID = str(d['id']) - - order.direction = directionMapReverse.get(d['side'], DIRECTION_UNKNOWN) - order.offset = OFFSET_NONE - order.status = STATUS_NOTTRADED # OANDA查询到的订单都是活动委托 - - order.price = d['price'] - order.totalVolume = d['units'] - order.orderTime = getTime(d['time']) - - order.vtOrderID = '.'.join([self.gatewayName , order.orderID]) - - self.gateway.onOrder(order) - - self.orderDict[order.orderID] = order - - self.writeLog(u'委托信息查询完成') - - #---------------------------------------------------------------------- - def onGetPositions(self, data, reqID): - """回调函数""" - if not 'positions' in data: - return - l = data['positions'] - - for d in l: - pos = VtPositionData() - pos.gatewayName = self.gatewayName - - pos.symbol = d['instrument'] - pos.exchange = EXCHANGE_OANDA - pos.vtSymbol = '.'.join([pos.symbol, pos.exchange]) - pos.direction = directionMapReverse.get(d['side'], DIRECTION_UNKNOWN) - pos.position = d['units'] - pos.price = d['avgPrice'] - pos.vtPositionName = '.'.join([pos.vtSymbol, pos.direction]) - - self.gateway.onPosition(pos) - - #---------------------------------------------------------------------- - def onGetTransactions(self, data, reqID): - """回调函数""" - if not 'transactions' in data: - return - l = data['transactions'] - - for d in l: - # 这里我们只关心委托成交 - if d['type'] == 'ORDER_FILLED': - trade = VtTradeData() - trade.gatewayName = self.gatewayName - - trade.symbol = d['instrument'] - trade.exchange = EXCHANGE_OANDA - trade.vtSymbol = '.'.join([trade.symbol, trade.exchange]) - trade.tradeID = str(d['id']) - trade.vtTradeID = '.'.join([self.gatewayName, trade.tradeID]) - trade.orderID = str(d['orderId']) - trade.vtOrderID = '.'.join([self.gatewayName, trade.orderID]) - trade.direction = directionMapReverse.get(d['side'], DIRECTION_UNKNOWN) - trade.offset = OFFSET_NONE - trade.price = d['price'] - trade.volume = d['units'] - trade.tradeTime = getTime(d['time']) - - self.gateway.onTrade(trade) - - self.writeLog(u'成交信息查询完成') - - #---------------------------------------------------------------------- - def onPrice(self, data): - """行情推送""" - if 'tick' not in data: - return - d = data['tick'] - - tick = VtTickData() - tick.gatewayName = self.gatewayName - - tick.symbol = d['instrument'] - tick.exchange = EXCHANGE_OANDA - tick.vtSymbol = '.'.join([tick.symbol, tick.exchange]) - tick.bidPrice1 = d['bid'] - tick.askPrice1 = d['ask'] - tick.time = getTime(d['time']) + '.0' # 补齐毫秒部分 - tick.date = datetime.datetime.utcnow().strftime('%Y%m%d') # OANDA的时间是UTC标准时 - - # 做市商的TICK数据只有买卖的报价,因此最新价格选用中间价代替 - tick.lastPrice = (tick.bidPrice1 + tick.askPrice1)/2 - - self.gateway.onTick(tick) - - #---------------------------------------------------------------------- - def onEvent(self, data): - """事件推送(成交等)""" - if 'transaction' not in data: - return - - d = data['transaction'] - - # 委托成交 - if d['type'] == 'ORDER_FILLED': - # 推送成交事件 - trade = VtTradeData() - trade.gatewayName = self.gatewayName - - trade.symbol = d['instrument'] - trade.exchange = EXCHANGE_OANDA - trade.vtSymbol = '.'.join([trade.symbol, trade.exchange]) - - trade.tradeID = str(d['id']) - trade.vtTradeID = '.'.join([self.gatewayName, trade.tradeID]) - - trade.orderID = str(d['orderId']) - trade.vtOrderID = '.'.join([self.gatewayName, trade.orderID]) - - trade.direction = directionMapReverse.get(d['side'], DIRECTION_UNKNOWN) - trade.offset = OFFSET_NONE - - trade.price = d['price'] - trade.volume = d['units'] - trade.tradeTime = getTime(d['time']) - - self.gateway.onTrade(trade) - - # 推送委托事件 - order = self.orderDict.get(str(d['orderId']), None) - if not order: - return - order.status = STATUS_ALLTRADED - self.gateway.onOrder(order) - - # 委托下达 - elif d['type'] in ['MARKET_ORDER_CREATE', 'LIMIT_ORDER_CREATE']: - order = VtOrderData() - order.gatewayName = self.gatewayName - - order.symbol = d['instrument'] - order.exchange = EXCHANGE_OANDA - order.vtSymbol = '.'.join([order.symbol, order.exchange]) - order.orderID = str(d['id']) - order.direction = directionMapReverse.get(d['side'], DIRECTION_UNKNOWN) - order.offset = OFFSET_NONE - order.status = STATUS_NOTTRADED - order.price = d['price'] - order.totalVolume = d['units'] - order.orderTime = getTime(d['time']) - order.vtOrderID = '.'.join([self.gatewayName , order.orderID]) - - self.gateway.onOrder(order) - self.orderDict[order.orderID] = order - - # 委托撤销 - elif d['type'] == 'ORDER_CANCEL': - order = self.orderDict.get(str(d['orderId']), None) - if not order: - return - order.status = STATUS_CANCELLED - self.gateway.onOrder(order) - - #---------------------------------------------------------------------- - def writeLog(self, logContent): - """发出日志""" - log = VtLogData() - log.gatewayName = self.gatewayName - log.logContent = logContent - self.gateway.onLog(log) - - #---------------------------------------------------------------------- - def qryInstruments(self): - """查询合约""" - params = {'accountId': self.accountId} - self.getInstruments(params) - - #---------------------------------------------------------------------- - def qryOrders(self): - """查询委托""" - self.getOrders({}) - - #---------------------------------------------------------------------- - def qryTrades(self): - """查询成交""" - # 最多查询100条记录 - self.getTransactions({'count': 100}) - - #---------------------------------------------------------------------- - def sendOrder_(self, orderReq): - """发送委托""" - params = {} - params['instrument'] = orderReq.symbol - params['units'] = orderReq.volume - params['side'] = directionMap.get(orderReq.direction, '') - params['price'] = orderReq.price - params['type'] = priceTypeMap.get(orderReq.priceType, '') - - # 委托有效期24小时 - expire = datetime.datetime.now() + datetime.timedelta(days=1) - params['expiry'] = expire.isoformat('T') + 'Z' - - self.sendOrder(params) - - #---------------------------------------------------------------------- - def cancelOrder_(self, cancelOrderReq): - """撤销委托""" - self.cancelOrder(cancelOrderReq.orderID) - - -#---------------------------------------------------------------------- -def getTime(t): - """把OANDA返回的时间格式转化为简单的时间字符串""" - return t[11:19] \ No newline at end of file diff --git a/vnpy/trader/language/chinese/constant.py b/vnpy/trader/language/chinese/constant.py index 68d35f6b..08743346 100644 --- a/vnpy/trader/language/chinese/constant.py +++ b/vnpy/trader/language/chinese/constant.py @@ -80,7 +80,6 @@ EXCHANGE_CME = 'CME' # CME交易所 EXCHANGE_ICE = 'ICE' # ICE交易所 EXCHANGE_LME = 'LME' # LME交易所 -EXCHANGE_OANDA = 'OANDA' # OANDA外汇做市商 EXCHANGE_FXCM = 'FXCM' # FXCM外汇做市商 EXCHANGE_OKCOIN = 'OKCOIN' # OKCOIN比特币交易所 diff --git a/vnpy/trader/language/english/constant.py b/vnpy/trader/language/english/constant.py index 23c61bd3..b5caeabe 100644 --- a/vnpy/trader/language/english/constant.py +++ b/vnpy/trader/language/english/constant.py @@ -76,7 +76,6 @@ EXCHANGE_CME = 'CME' # CME交易所 EXCHANGE_ICE = 'ICE' # ICE交易所 EXCHANGE_LME = 'LME' # LME交易所 -EXCHANGE_OANDA = 'OANDA' # OANDA外汇做市商 EXCHANGE_FXCM = 'FXCM' # FXCM外汇做市商 EXCHANGE_OKCOIN = 'OKCOIN' # OKCOIN比特币交易所