From b2fc3e5d84f3925426ab97b3c327ef76f9dcb647 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Thu, 25 Jan 2018 16:24:08 +0800 Subject: [PATCH] =?UTF-8?q?[Mod]=E5=AE=8C=E5=96=84FxcmApi=E7=9A=84?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=8E=A8=E9=80=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/api/fxcm/README.md | 18 ++ vnpy/api/fxcm/__init__.py | 3 + vnpy/api/fxcm/demo.py | 429 -------------------------------------- vnpy/api/fxcm/test.py | 24 +++ vnpy/api/fxcm/vnfxcm.py | 67 +++--- 5 files changed, 77 insertions(+), 464 deletions(-) create mode 100644 vnpy/api/fxcm/README.md create mode 100644 vnpy/api/fxcm/__init__.py delete mode 100644 vnpy/api/fxcm/demo.py create mode 100644 vnpy/api/fxcm/test.py diff --git a/vnpy/api/fxcm/README.md b/vnpy/api/fxcm/README.md new file mode 100644 index 00000000..f3f2faa0 --- /dev/null +++ b/vnpy/api/fxcm/README.md @@ -0,0 +1,18 @@ +# vnpy.api.fxcm + +### 简介 +福汇(FXCM)外汇交易接口,基于REST API开发,实现了以下功能: + +1. 发送、修改、撤销委托 + +2. 查询可交易合约以及各交易表 + +3. 实时行情和交易表推送 + +### API版本 +版本:v2.0 + +日期:2018-01-16 + +链接:[https://github.com/FXCMAPI/RestAPI](https://github.com/FXCMAPI/RestAPI) + diff --git a/vnpy/api/fxcm/__init__.py b/vnpy/api/fxcm/__init__.py new file mode 100644 index 00000000..824509ee --- /dev/null +++ b/vnpy/api/fxcm/__init__.py @@ -0,0 +1,3 @@ +# encoding: UTF-8 + +from vnfxcm import FxcmApi \ No newline at end of file diff --git a/vnpy/api/fxcm/demo.py b/vnpy/api/fxcm/demo.py deleted file mode 100644 index b405f3f3..00000000 --- a/vnpy/api/fxcm/demo.py +++ /dev/null @@ -1,429 +0,0 @@ -""" -FXCM Trading RESTful API example. -""" -import json -import time -import requests -from socketIO_client import SocketIO -from prompt_toolkit import prompt -from threading import Thread -import signal -import sys -import io -from datetime import datetime - -socketIO = None -UPDATES = {} -SYMBOLS = {} -COLLECTIONS = None -ACCESS_TOKEN = "48055b5d9afac0a300143ac067ce04cd2430a434" -TRADING_API_URL = 'https://api-demo.fxcm.com:443' -WEBSOCKET_PORT = 443 - - -list = ['Offer','Account','Order','OpenPosition','Summary','Properties', 'ClosedPosition'] -order_list = [] -logFile = "H:/Projects/RESTAPI-master/nodejs/PythonLog.txt" - -def timestamp(): - output = str(datetime.now().strftime('%Y%m%d-%H:%M:%S.%f')[:-3]) - return output - -def logging(mess, t): - ts = timestamp() - - with io.FileIO(logFile, "a") as file: - file.write('\n' +ts + ": " +t + " ==>" +'\n') - for key in mess: - file.write(str(key) +" - " +str(mess[key]) +'\n') - -def request_processor(method, params): - """ Trading server request help function. """ - - headers = { - 'User-Agent': 'request', - 'Authorization': bearer_access_token, - 'Accept': 'application/json', - 'Content-Type': 'application/x-www-form-urlencoded' - } - rresp = requests.get(TRADING_API_URL + method, headers=headers, params=params) - if rresp.status_code == 200: - data = rresp.json() - if data["response"]["executed"] is True: - return True, data - return False, data["response"]["error"] - else: - return False, rresp.status_code - -def post_request_processor(method, params): - """ Trading server request help function. """ - - headers = { - 'User-Agent': 'request', - 'Authorization': bearer_access_token, - 'Accept': 'application/json', - 'Content-Type': 'application/x-www-form-urlencoded' - } - rresp = requests.post(TRADING_API_URL + method, headers=headers, data=params) - if rresp.status_code == 200: - data = rresp.json() - if data["response"]["executed"] is True: - return True, data - return False, data["response"]["error"] - else: - return False, rresp.status_code - -def create_bearer_token(t,s): - bt = "Bearer " +s +t - return bt - -def on_price_update(msg): - md = json.loads(msg) - SYMBOLS[md["Symbol"]] = md - print(SYMBOLS, "SYMBOLS") - #logging(SYMBOLS, "SYMBOLS") - -def on_message(msg): - message = json.loads(msg) - UPDATES[message["t"]] = message - print(UPDATES, "UPDATES") - #logging(UPDATES, "UPDATES") - -def on_error(ws, error): - print (error) - -def on_close(): - print ('Websocket closed.') - -def on_connect(): - - - ### Get models - status, response = request_processor('/trading/get_model', {'models': list}) - if status is True: - COLLECTIONS = response - print("*" * 50) - print (COLLECTIONS["accounts"]) - print("*" * 50) - else: - print(status) - print ("Error processing request /trading/get_model: " +str(response)) - ### Subscribe message updates - status, response = post_request_processor('/trading/subscribe', {'models': order_list}) - if status is True: - for item in order_list: - socketIO.on(item, on_message) - else: - print ("Error processing request: /trading/subscribe: " + response) - - thr = Thread(target=cli, args=(1, COLLECTIONS)) - try: - thr.setDaemon(True) - thr.start() - socketIO.wait() - except (KeyboardInterrupt, SystemExit): - thr.join(0) - sys.exit(1) - - -def subscribe_prices(symbol): - status, response = post_request_processor('/subscribe', {'pairs': symbol}) - if status is True: - socketIO.on(symbol, on_price_update) - print response - else: - print ("Error processing request: /subscribe: " + response) - -def unsubscribe_prices(symbol): - status, response = post_request_processor('/unsubscribe', {'pairs': symbol}) - if status is True: - socketIO.on(symbol, on_price_update) - else: - print ("Error processing request: /unsubscribe: " + response) - -def cli(args, COLLECTIONS): - while True: - try: - inp = prompt(u'> ') - except KeyboardInterrupt: - print ("Press Ctrl+c again to quit.") - sys.exit(1) - if not inp: - continue - try: - if len(inp) > 3 and inp[0:3] == 'run': - cmd = json.loads(inp[4:]) - command = cmd["c"] - if command == 'book': - for symbol in SYMBOLS: - price = SYMBOLS[symbol] - print (price) - - elif command == 'show': - if cmd["opt"] == 'offers': - for offer in COLLECTIONS['offers']: - ###print ('{}, {}, {}, {}, {}'.format(offer['currency'], offer['sell'], offer['buy'], offer['offerId'], offer['ratePrecision'])) - print (offer) - - elif cmd["opt"] == 'orders': - for order in COLLECTIONS['orders']: - print (order) - - elif cmd["opt"] == 'updates': - for obj in UPDATES: - print (obj) - - elif cmd["opt"] == 'accounts': - for obj in COLLECTIONS['accounts']: - print (obj) - - elif cmd["opt"] == 'open_positions': - for obj in COLLECTIONS['open_positions']: - print (obj) - - elif cmd["opt"] == 'closed_positions': - for obj in COLLECTIONS['closed_positions']: - print (obj) - - elif cmd["opt"] == 'summary': - for obj in COLLECTIONS['summary']: - print (obj) - - elif cmd["opt"] == 'properties': - for obj in COLLECTIONS['properties']: - print (obj) - - elif cmd["opt"] == 'LeverageProfile': - for obj in COLLECTIONS['LeverageProfile']: - print (obj) - - elif command == 'subscribe': - for symbol in cmd["opt"]: - subscribe_prices(symbol) - - elif command == 'unsubscribe': - for symbol in cmd["opt"]: - unsubscribe_prices(symbol) - - elif command == 'market_order': - status, response = post_request_processor('/trading/open_trade', { - 'account_id': cmd['account_id'], - 'symbol': cmd['symbol'], - 'side': cmd['side'], - 'amount': cmd['amount'], - 'at_market': 0, - 'order_type': 'AtMarket', - 'time_in_force': cmd['time_in_force'] - }) - if status is True: - print ('market_order has been executed: {}'.format(response)) - else: - print ('market_order execution error: {}'.format(response)) - - elif command == 'market_range': - status, response = post_request_processor('/trading/open_trade', { - 'account_id': cmd['account_id'], - 'symbol': cmd['symbol'], - 'side': cmd['side'], - 'amount': cmd['amount'], - 'order_type': 'MarketRange', - 'at_market': 1 - }) - if status is True: - print ('market_order has been executed: {}'.format(response)) - else: - print ('market_order execution error: {}'.format(response)) - - elif command == 'close_trade': - status, response = post_request_processor('/trading/close_trade', { - 'trade_id': cmd['trade_id'], - 'rate': 0, - 'amount': cmd['amount'], - 'at_market': 0, - 'order_type': 'AtMarket', - 'time_in_force': cmd['time_in_force'] - }) - if status is True: - print ('close_trade has been executed: {}'.format(response)) - else: - print ('close_trade execution error: {}'.format(response)) - - elif command == 'create_entry_order': - status, response = post_request_processor('/trading/create_entry_order', { - 'account_id': cmd['account_id'], - 'symbol': cmd['symbol'], - 'is_buy': cmd['side'], - 'rate': cmd['rate'], - 'is_in_pips': 0, - 'amount': cmd['amount'], - 'order_type': 'AtMarket', - 'time_in_force': cmd['time_in_force'] - }) - if status is True: - print ('create_entry_order has been executed: {}'.format(response)) - else: - print ('create_entry_order execution error: {}'.format(response)) - - elif command == 'change_order': - status, response = post_request_processor('/trading/change_order', { - 'order_id': cmd['order_id'], - 'rate': cmd['rate'], - 'range': cmd['range'], - 'amount': cmd['amount'], - 'trailing_step': cmd['trailing_step'] - }) - if status is True: - print ('change_order has been executed: {}'.format(response)) - else: - print ('change_order execution error: {}'.format(response)) - - elif command == 'delete_order': - status, response = post_request_processor('/trading/delete_order', { - 'order_id': cmd['order_id'] - }) - if status is True: - print ('delete_order has been executed: {}'.format(response)) - else: - print ('delete_order execution error: {}'.format(response)) - - elif command == 'get_instruments': - status, response = request_processor('/trading/get_instruments', {}) - if status is True: - print ('get_instruments has been executed: {}'.format(response)) - else: - print ('get_instruments execution error: {}'.format(response)) - - elif command == 'simple_oco': - status, response = request_processor('/trading/simple_oco', { - 'account_id': cmd['account_id'], - 'symbol': cmd['symbol'], - 'amount': cmd['amount'], - 'time_in_force': cmd['time_in_force'], - 'is_buy': cmd['is_buy'], - 'rate': cmd['rate'], - 'is_buy2': cmd['is_buy2'], - 'rate2': cmd['rate2'] - }) - if status is True: - print ('simple_oco has been executed: {}'.format(response)) - else: - print ('simple_oco execution error: {}'.format(response)) - - elif command == 'add_to_oco': - status, response = request_processor('/trading/add_to_oco', { - orderIds: cmd.orderIds, - ocoBulkId: cmd.ocoBulkId - }) - if status is True: - print ('add_to_oco has been executed: {}'.format(response)) - else: - print ('add_to_oco execution error: {}'.format(response)) - - elif command == 'remove_from_oco': - status, response = request_processor('/trading/remove_from_oco', { - orderIds: cmd.orderIds - }) - if status is True: - print ('remove_from_oco has been executed: {}'.format(response)) - else: - print ('remove_from_oco execution error: {}'.format(response)) - - elif command == 'edit_oco': - status, response = request_processor('/trading/edit_oco', { - ocoBulkId: cmd.ocoBulkId, - addOrderIds: cmd.addOrderIds, - removeOrderIds: cmd.removeOrderIds - }) - if status is True: - print ('edit_oco has been executed: {}'.format(response)) - else: - print ('edit_oco execution error: {}'.format(response)) - - elif command == 'change_trade_stop_limit': - status, response = request_processor('/trading/change_trade_stop_limit', { - trade_id: cmd.trade_id, - is_stop: cmd.is_stop, - rate: cmd.rate, - is_in_pips: cmd.is_in_pips, - trailing_step: cmd.trailing_step - }) - if status is True: - print ('change_trade_stop_limit has been executed: {}'.format(response)) - else: - print ('change_trade_stop_limit execution error: {}'.format(response)) - - elif command == 'change_order_stop_limit': - status, response = request_processor('/trading/change_order_stop_limit', { - order_id: cmd.order_id, - is_stop: cmd.is_stop, - rate: cmd.rate, - is_in_pips: cmd.is_in_pips, - trailing_step: cmd.trailing_step - }) - if status is True: - print ('change_order_stop_limit has been executed: {}'.format(response)) - else: - print ('change_order_stop_limit execution error: {}'.format(response)) - - elif command == 'change_net_stop_limit': - status, response = request_processor('/trading/change_net_stop_limit', { - account_id: cmd.account_id, - symbol: cmd.symbol, - is_buy: cmd.is_buy, - is_stop: cmd.is_stop, - rate: cmd.rate, - trailing_step: cmd.trailing_step - }) - if status is True: - print ('change_net_stop_limit has been executed: {}'.format(response)) - else: - print ('change_net_stop_limit execution error: {}'.format(response)) - - elif command == 'close_all_for_symbol': - status, response = request_processor('/trading/close_all_for_symbol', { - account_id: cmd.account_id, - forSymbol: cmd.forSymbol, - symbol: cmd.symbol, - order_type: cmd.order_type, - time_in_force: cmd.time_in_force - }) - if status is True: - print ('close_all_for_symbol has been executed: {}'.format(response)) - else: - print ('close_all_for_symbol execution error: {}'.format(response)) - - elif command == 'candles': - req="/"+command+"/"+str(cmd['instrumentid'])+"/"+str(cmd['periodid']) - status, response = request_processor(req, { - 'num': cmd['num'], - 'from': cmd['from'], - 'to': cmd['to'] - }) - if status is True: - print ('has been executed: {}'.format(response)) - else: - print ('execution error: {}'.format(response)) - - - else: - print ("Unknown command: " + command) - else: - print ('Unknown command.') - except ValueError: - print ('Invalid command') -### Main - -if __name__ == '__main__': - #signal.getsignal(signal.SIGINT, exit_gracefully) - - COLLECTIONS = {} - print '000' - socketIO = SocketIO(TRADING_API_URL, WEBSOCKET_PORT, params={'access_token': ACCESS_TOKEN, 'agent': "leiwang-rest-api"}) - print 1 - #print (socketIO._engineIO_session.id) - bearer_access_token = create_bearer_token(ACCESS_TOKEN, socketIO._engineIO_session.id) - print (bearer_access_token) - socketIO.on('disconnec', on_close) - socketIO.on('connect', on_connect) - subscribe_prices('EUR/USD') - socketIO.wait() diff --git a/vnpy/api/fxcm/test.py b/vnpy/api/fxcm/test.py new file mode 100644 index 00000000..595cd78d --- /dev/null +++ b/vnpy/api/fxcm/test.py @@ -0,0 +1,24 @@ +# encoding: UTF-8 + +from vnfxcm import FxcmApi + +url = 'https://api-demo.fxcm.com:443' +port = 443 +token = '48055b5d9afac0a300143ac067ce04cd2430a434' +proxy = 'https://localhost:1080' + +api = FxcmApi() +print 'api created' + +api.connect(url, port, token, proxy) +print api.bearer + +#api.getInstruments() + +api.subscribe('EUR/USD') +api.subscribe('USD/JPY') +api.subscribe('GBP/USD') +#api.getModel('Summary') +#api.subscribeModel('Summary') + +input() \ No newline at end of file diff --git a/vnpy/api/fxcm/vnfxcm.py b/vnpy/api/fxcm/vnfxcm.py index dc47ad90..a96b601a 100644 --- a/vnpy/api/fxcm/vnfxcm.py +++ b/vnpy/api/fxcm/vnfxcm.py @@ -5,7 +5,6 @@ import requests from socketIO_client import SocketIO from threading import Thread from queue import Queue, Empty -from datetime import datetime ######################################################################## @@ -15,6 +14,14 @@ class FxcmApi(object): WEBSOCKET_PORT = 443 METHOD_GET = 'get' METHOD_POST = 'post' + + MODEL_OFFER = 'Offer' + MODEL_ACCOUNT = 'Account' + MODEL_ORDER = 'Order' + MODEL_OPENPOSITION = 'OpenPosition' + MODEL_SUMMARY = 'Summary' + MODEL_PROPERTIES = 'Properties' + MODEL_CLOSEDPOSITION = 'ClosedPosition' #---------------------------------------------------------------------- def __init__(self): @@ -22,6 +29,7 @@ class FxcmApi(object): self.url = '' self.port = '' self.token = '' + self.proxy = '' self.sio = None self.bearer = '' @@ -30,27 +38,34 @@ class FxcmApi(object): self.queue = Queue() self.reqid = 0 self.active = False - self.thread = Thread(target=self.run) + self.reqThread = Thread(target=self.run) #---------------------------------------------------------------------- - def connect(self, url, port, token): + def connect(self, url, port, token, proxy=''): """连接""" self.url = url self.port = port self.token = token + self.proxy = proxy self.initSocketIO() self.generateBearer() self.generateHeaders() self.active = True - self.thread.start() + self.reqThread.start() + + self.sioThread = Thread(target=self.sio.wait) + self.sioThread.start() #---------------------------------------------------------------------- def stop(self): """停止""" self.active = False - self.thread.join() + self.reqThread.join() + + self.sio._close() + self.sioThread.join() #---------------------------------------------------------------------- def initSocketIO(self): @@ -59,7 +74,12 @@ class FxcmApi(object): 'access_token': self.token, 'agent': "leiwang-rest-api" } - self.sio = SocketIO(self.url, self.port, params=params) + + proxy = {} + if self.proxy: + proxy['https'] = self.proxy + + self.sio = SocketIO(self.url, self.port, params=params, proxies=proxy) self.sio.on('connect', self.onConnect) self.sio.on('disconnect', self.onDisconnect) @@ -117,10 +137,14 @@ class FxcmApi(object): url = self.url + uri + proxy = {} + if self.proxy: + proxy['https'] = self.proxy + if method == self.METHOD_GET: - resp = requests.get(url, headers=self.headers, params=params) + resp = requests.get(url, headers=self.headers, params=params, proxies=proxy) elif method == self.METHOD_POST: - resp = requests.post(url, headers=self.headers, data=params) + resp = requests.post(url, headers=self.headers, data=params, proxies=proxy) if resp.status_code == 200: data = resp.json() @@ -327,32 +351,5 @@ class FxcmApi(object): def onModelUpdate(self, data): """表推送""" print data - - - - - - -if __name__ == '__main__': - url = 'https://api-demo.fxcm.com:443' - port = 443 - token = '48055b5d9afac0a300143ac067ce04cd2430a434' - - api = FxcmApi() - print 'api created' - - api.connect(url, port, token) - print api.bearer - - #api.getInstruments() - - api.subscribe('EUR/USD') - #api.subscribe(u'USD') - #api.subscribe(u'eurusd') - #api.getModel('Summary') - #api.subscribeModel('Summary') - - input() - \ No newline at end of file