diff --git a/.gitignore b/.gitignore index 11ef5d2..6a715da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *~ *.py[co] +__pycache__ # Packages *.egg diff --git a/backtest/backtest.py b/backtest/backtest.py index 10e0a29..4749ed1 100644 --- a/backtest/backtest.py +++ b/backtest/backtest.py @@ -1,5 +1,10 @@ +from __future__ import print_function + import copy -import Queue +try: + import Queue as queue +except ImportError: + import queue import threading import time from decimal import Decimal, getcontext @@ -28,7 +33,7 @@ def backtest( ticker.stream_next_tick() try: event = events.get(False) - except Queue.Empty: + except queue.Empty: pass else: if event is not None: @@ -45,14 +50,14 @@ def backtest( if __name__ == "__main__": heartbeat = 0.0 - events = Queue.Queue() + events = queue.Queue() equity = settings.EQUITY # Load the historic CSV tick data files pairs = ["GBPUSD"] csv_dir = settings.CSV_DATA_DIR if csv_dir is None: - print "No historic data directory provided - backtest terminating." + print("No historic data directory provided - backtest terminating.") sys.exit() # Create the historic tick data streaming class diff --git a/data/price.py b/data/price.py index 06a203e..2136fdb 100644 --- a/data/price.py +++ b/data/price.py @@ -1,5 +1,5 @@ import datetime -from decimal import Decimal, ROUND_HALF_DOWN +from decimal import Decimal, getcontext, ROUND_HALF_DOWN import os import os.path import time @@ -59,12 +59,13 @@ class PriceHandler(object): 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", ROUND_HALF_DOWN) + Decimal("0.00001") ) inv_ask = (Decimal("1.0")/ask).quantize( - Decimal("0.00001", ROUND_HALF_DOWN) + Decimal("0.00001") ) return inv_pair, inv_bid, inv_ask @@ -129,16 +130,17 @@ class HistoricCSVPriceHandler(PriceHandler): well as updating the current bid/ask and inverse bid/ask. """ try: - index, row = self.all_pairs.next() + index, row = next(self.all_pairs) except StopIteration: return else: + getcontext().rounding = ROUND_HALF_DOWN pair = row["Pair"] bid = Decimal(str(row["Bid"])).quantize( - Decimal("0.00001", ROUND_HALF_DOWN) + Decimal("0.00001") ) ask = Decimal(str(row["Ask"])).quantize( - Decimal("0.00001", ROUND_HALF_DOWN) + Decimal("0.00001") ) # Create decimalised prices for traded pair diff --git a/data/streaming.py b/data/streaming.py index 66d80eb..fed07ea 100644 --- a/data/streaming.py +++ b/data/streaming.py @@ -1,4 +1,6 @@ -from decimal import Decimal, ROUND_HALF_DOWN +from __future__ import print_function + +from decimal import Decimal, getcontext, ROUND_HALF_DOWN import requests import json @@ -24,18 +26,20 @@ class StreamingForexPrices(PriceHandler): 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", ROUND_HALF_DOWN) + Decimal("0.00001") ) inv_ask = (Decimal("1.0")/ask).quantize( - Decimal("0.00001", ROUND_HALF_DOWN) + 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] try: + requests.packages.urllib3.disable_warnings() s = requests.Session() url = "https://" + self.domain + "/v1/prices" headers = {'Authorization' : 'Bearer ' + self.access_token} @@ -46,7 +50,7 @@ class StreamingForexPrices(PriceHandler): return resp except Exception as e: s.close() - print "Caught exception when connecting to stream\n" + str(e) + print("Caught exception when connecting to stream\n" + str(e)) def stream_to_queue(self): response = self.connect_to_stream() @@ -55,19 +59,21 @@ class StreamingForexPrices(PriceHandler): for line in response.iter_lines(1): if line: try: - msg = json.loads(line) + dline = line.decode('utf-8') + msg = json.loads(dline) except Exception as e: - print "Caught exception when converting message into json\n" + str(e) + print("Caught exception when converting message into json\n" + str(e)) return - if msg.has_key("instrument") or msg.has_key("tick"): - print msg + if "instrument" in msg or "tick" in msg: + print(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", ROUND_HALF_DOWN) + Decimal("0.00001") ) ask = Decimal(str(msg["tick"]["ask"])).quantize( - Decimal("0.00001", ROUND_HALF_DOWN) + Decimal("0.00001") ) self.prices[instrument]["bid"] = bid self.prices[instrument]["ask"] = ask diff --git a/execution/execution.py b/execution/execution.py index 6f5c217..1f4ff40 100644 --- a/execution/execution.py +++ b/execution/execution.py @@ -1,6 +1,16 @@ +from __future__ import print_function + from abc import ABCMeta, abstractmethod -import httplib -import urllib +try: + import httplib +except ImportError: + import http.client as httplib +try: + from urllib import urlencode +except ImportError: + from urllib.parse import urlencode +import urllib3 +urllib3.disable_warnings() class ExecutionHandler(object): @@ -47,7 +57,7 @@ class OANDAExecutionHandler(ExecutionHandler): "Content-Type": "application/x-www-form-urlencoded", "Authorization": "Bearer " + self.access_token } - params = urllib.urlencode({ + params = urlencode({ "instrument" : instrument, "units" : event.units, "type" : event.order_type, @@ -59,5 +69,5 @@ class OANDAExecutionHandler(ExecutionHandler): params, headers ) response = self.conn.getresponse().read() - print response + print(response) \ No newline at end of file diff --git a/portfolio/portfolio.py b/portfolio/portfolio.py index d004efe..d24408c 100644 --- a/portfolio/portfolio.py +++ b/portfolio/portfolio.py @@ -1,3 +1,5 @@ +from __future__ import print_function + from copy import deepcopy from decimal import Decimal, getcontext, ROUND_HALF_DOWN import os @@ -73,7 +75,7 @@ class Portfolio(object): out_file = os.path.join(OUTPUT_RESULTS_DIR, filename) df_equity = pd.DataFrame.from_records(self.equity, index='time') df_equity.to_csv(out_file) - print "Simulation complete and results exported to %s" % filename + print("Simulation complete and results exported to %s" % filename) def execute_signal(self, signal_event): side = signal_event.side @@ -123,5 +125,6 @@ class Portfolio(object): order = OrderEvent(currency_pair, units, "market", side) self.events.put(order) - print "Balance: %0.2f" % self.balance - self.append_equity_row(time, self.balance) \ No newline at end of file + print("Balance: %0.2f" % self.balance) + self.append_equity_row(time, self.balance) + \ No newline at end of file diff --git a/portfolio/position.py b/portfolio/position.py index 1577e70..f2fc385 100644 --- a/portfolio/position.py +++ b/portfolio/position.py @@ -92,7 +92,8 @@ class Position(object): self.update_position_price() # Calculate PnL pnl = self.calculate_pips() * qh_close * dec_units - return pnl.quantize(Decimal("0.01", ROUND_HALF_DOWN)) + getcontext().rounding = ROUND_HALF_DOWN + return pnl.quantize(Decimal("0.01")) def close_position(self): ticker_cp = self.ticker.prices[self.currency_pair] @@ -106,4 +107,5 @@ class Position(object): self.update_position_price() # Calculate PnL pnl = self.calculate_pips() * qh_close * self.units - return pnl.quantize(Decimal("0.01", ROUND_HALF_DOWN)) + getcontext().rounding = ROUND_HALF_DOWN + return pnl.quantize(Decimal("0.01")) diff --git a/portfolio/position_test.py b/portfolio/position_test.py index a0f1c62..9486298 100644 --- a/portfolio/position_test.py +++ b/portfolio/position_test.py @@ -1,4 +1,4 @@ -from decimal import Decimal, getcontext +from decimal import Decimal import unittest from position import Position @@ -28,7 +28,6 @@ class TestLongGBPUSDPosition(unittest.TestCase): denominated currency of GBP, using 2,000 units of GBP/USD. """ def setUp(self): - getcontext.prec = 2 home_currency = "GBP" position_type = "long" currency_pair = "GBPUSD" @@ -78,7 +77,6 @@ class TestShortGBPUSDPosition(unittest.TestCase): denominated currency of GBP, using 2,000 units of GBP/USD. """ def setUp(self): - getcontext.prec = 2 home_currency = "GBP" position_type = "short" currency_pair = "GBPUSD" @@ -132,7 +130,6 @@ class TestLongEURUSDPosition(unittest.TestCase): denominated currency of GBP, using 2,000 units of EUR/USD. """ def setUp(self): - getcontext.prec = 2 home_currency = "GBP" position_type = "long" currency_pair = "EURUSD" @@ -183,7 +180,6 @@ class TestLongEURUSDPosition(unittest.TestCase): denominated currency of GBP, using 2,000 units of EUR/USD. """ def setUp(self): - getcontext.prec = 2 home_currency = "GBP" position_type = "short" currency_pair = "EURUSD" diff --git a/trading/trading.py b/trading/trading.py index f8cc90d..f2d38e7 100644 --- a/trading/trading.py +++ b/trading/trading.py @@ -1,8 +1,11 @@ import copy -import Queue +from decimal import Decimal, getcontext +try: + import Queue as queue +except ImportError: + import queue import threading import time -from decimal import Decimal, getcontext from qsforex.execution.execution import OANDAExecutionHandler from qsforex.portfolio.portfolio import Portfolio @@ -22,7 +25,7 @@ def trade(events, strategy, portfolio, execution, heartbeat): while True: try: event = events.get(False) - except Queue.Empty: + except queue.Empty: pass else: if event is not None: @@ -40,7 +43,7 @@ if __name__ == "__main__": getcontext().prec = 2 heartbeat = 0.0 # Half a second between polling - events = Queue.Queue() + events = queue.Queue() equity = settings.EQUITY # Trade "Cable" @@ -81,4 +84,4 @@ if __name__ == "__main__": # Start both threads trade_thread.start() - price_thread.start() \ No newline at end of file + price_thread.start()