93 lines
3.6 KiB
Python
93 lines
3.6 KiB
Python
from __future__ import print_function
|
|
|
|
from decimal import Decimal, getcontext, ROUND_HALF_DOWN
|
|
import logging
|
|
import json
|
|
|
|
import requests
|
|
|
|
from qsforex.event.event import TickEvent
|
|
from qsforex.data.price import PriceHandler
|
|
|
|
|
|
class StreamingForexPrices(PriceHandler):
|
|
def __init__(
|
|
self, domain, access_token,
|
|
account_id, pairs, events_queue
|
|
):
|
|
self.domain = domain
|
|
self.access_token = access_token
|
|
self.account_id = account_id
|
|
self.events_queue = events_queue
|
|
self.pairs = pairs
|
|
self.prices = self._set_up_prices_dict()
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
def invert_prices(self, pair, bid, ask):
|
|
"""
|
|
Simply inverts the prices for a particular currency pair.
|
|
This will turn the bid/ask of "GBPUSD" into bid/ask for
|
|
"USDGBP" and place them in the prices dictionary.
|
|
"""
|
|
getcontext().rounding = ROUND_HALF_DOWN
|
|
inv_pair = "%s%s" % (pair[3:], pair[:3])
|
|
inv_bid = (Decimal("1.0")/bid).quantize(
|
|
Decimal("0.00001")
|
|
)
|
|
inv_ask = (Decimal("1.0")/ask).quantize(
|
|
Decimal("0.00001")
|
|
)
|
|
return inv_pair, inv_bid, inv_ask
|
|
|
|
def connect_to_stream(self):
|
|
pairs_oanda = ["%s_%s" % (p[:3], p[3:]) for p in self.pairs]
|
|
pair_list = ",".join(pairs_oanda)
|
|
try:
|
|
requests.packages.urllib3.disable_warnings()
|
|
s = requests.Session()
|
|
url = "https://" + self.domain + "/v1/prices"
|
|
headers = {'Authorization' : 'Bearer ' + self.access_token}
|
|
params = {'instruments' : pair_list, 'accountId' : self.account_id}
|
|
req = requests.Request('GET', url, headers=headers, params=params)
|
|
pre = req.prepare()
|
|
resp = s.send(pre, stream=True, verify=False)
|
|
return resp
|
|
except Exception as e:
|
|
s.close()
|
|
print("Caught exception when connecting to stream\n" + str(e))
|
|
|
|
def stream_to_queue(self):
|
|
response = self.connect_to_stream()
|
|
if response.status_code != 200:
|
|
return
|
|
for line in response.iter_lines(1):
|
|
if line:
|
|
try:
|
|
dline = line.decode('utf-8')
|
|
msg = json.loads(dline)
|
|
except Exception as e:
|
|
self.logger.error(
|
|
"Caught exception when converting message into json: %s" % str(e)
|
|
)
|
|
return
|
|
if "instrument" in msg or "tick" in msg:
|
|
self.logger.debug(msg)
|
|
getcontext().rounding = ROUND_HALF_DOWN
|
|
instrument = msg["tick"]["instrument"].replace("_", "")
|
|
time = msg["tick"]["time"]
|
|
bid = Decimal(str(msg["tick"]["bid"])).quantize(
|
|
Decimal("0.00001")
|
|
)
|
|
ask = Decimal(str(msg["tick"]["ask"])).quantize(
|
|
Decimal("0.00001")
|
|
)
|
|
self.prices[instrument]["bid"] = bid
|
|
self.prices[instrument]["ask"] = ask
|
|
# Invert the prices (GBP_USD -> USD_GBP)
|
|
inv_pair, inv_bid, inv_ask = self.invert_prices(instrument, bid, ask)
|
|
self.prices[inv_pair]["bid"] = inv_bid
|
|
self.prices[inv_pair]["ask"] = inv_ask
|
|
self.prices[inv_pair]["time"] = time
|
|
tev = TickEvent(instrument, time, bid, ask)
|
|
self.events_queue.put(tev)
|