Added Python 2.7.x and 3.4.x compatibility to the code. Disabled HTTPS security warning in urllib3 package of 'requests' package.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
*~
|
*~
|
||||||
*.py[co]
|
*.py[co]
|
||||||
|
__pycache__
|
||||||
|
|
||||||
# Packages
|
# Packages
|
||||||
*.egg
|
*.egg
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import Queue
|
try:
|
||||||
|
import Queue as queue
|
||||||
|
except ImportError:
|
||||||
|
import queue
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from decimal import Decimal, getcontext
|
from decimal import Decimal, getcontext
|
||||||
@@ -28,7 +33,7 @@ def backtest(
|
|||||||
ticker.stream_next_tick()
|
ticker.stream_next_tick()
|
||||||
try:
|
try:
|
||||||
event = events.get(False)
|
event = events.get(False)
|
||||||
except Queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if event is not None:
|
if event is not None:
|
||||||
@@ -45,14 +50,14 @@ def backtest(
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
heartbeat = 0.0
|
heartbeat = 0.0
|
||||||
events = Queue.Queue()
|
events = queue.Queue()
|
||||||
equity = settings.EQUITY
|
equity = settings.EQUITY
|
||||||
|
|
||||||
# Load the historic CSV tick data files
|
# Load the historic CSV tick data files
|
||||||
pairs = ["GBPUSD"]
|
pairs = ["GBPUSD"]
|
||||||
csv_dir = settings.CSV_DATA_DIR
|
csv_dir = settings.CSV_DATA_DIR
|
||||||
if csv_dir is None:
|
if csv_dir is None:
|
||||||
print "No historic data directory provided - backtest terminating."
|
print("No historic data directory provided - backtest terminating.")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# Create the historic tick data streaming class
|
# Create the historic tick data streaming class
|
||||||
|
|||||||
+8
-6
@@ -1,5 +1,5 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from decimal import Decimal, ROUND_HALF_DOWN
|
from decimal import Decimal, getcontext, ROUND_HALF_DOWN
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import time
|
import time
|
||||||
@@ -59,12 +59,13 @@ class PriceHandler(object):
|
|||||||
This will turn the bid/ask of "GBPUSD" into bid/ask for
|
This will turn the bid/ask of "GBPUSD" into bid/ask for
|
||||||
"USDGBP" and place them in the prices dictionary.
|
"USDGBP" and place them in the prices dictionary.
|
||||||
"""
|
"""
|
||||||
|
getcontext().rounding = ROUND_HALF_DOWN
|
||||||
inv_pair = "%s%s" % (pair[3:], pair[:3])
|
inv_pair = "%s%s" % (pair[3:], pair[:3])
|
||||||
inv_bid = (Decimal("1.0")/bid).quantize(
|
inv_bid = (Decimal("1.0")/bid).quantize(
|
||||||
Decimal("0.00001", ROUND_HALF_DOWN)
|
Decimal("0.00001")
|
||||||
)
|
)
|
||||||
inv_ask = (Decimal("1.0")/ask).quantize(
|
inv_ask = (Decimal("1.0")/ask).quantize(
|
||||||
Decimal("0.00001", ROUND_HALF_DOWN)
|
Decimal("0.00001")
|
||||||
)
|
)
|
||||||
return inv_pair, inv_bid, inv_ask
|
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.
|
well as updating the current bid/ask and inverse bid/ask.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
index, row = self.all_pairs.next()
|
index, row = next(self.all_pairs)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
getcontext().rounding = ROUND_HALF_DOWN
|
||||||
pair = row["Pair"]
|
pair = row["Pair"]
|
||||||
bid = Decimal(str(row["Bid"])).quantize(
|
bid = Decimal(str(row["Bid"])).quantize(
|
||||||
Decimal("0.00001", ROUND_HALF_DOWN)
|
Decimal("0.00001")
|
||||||
)
|
)
|
||||||
ask = Decimal(str(row["Ask"])).quantize(
|
ask = Decimal(str(row["Ask"])).quantize(
|
||||||
Decimal("0.00001", ROUND_HALF_DOWN)
|
Decimal("0.00001")
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create decimalised prices for traded pair
|
# Create decimalised prices for traded pair
|
||||||
|
|||||||
+16
-10
@@ -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 requests
|
||||||
import json
|
import json
|
||||||
|
|
||||||
@@ -24,18 +26,20 @@ class StreamingForexPrices(PriceHandler):
|
|||||||
This will turn the bid/ask of "GBPUSD" into bid/ask for
|
This will turn the bid/ask of "GBPUSD" into bid/ask for
|
||||||
"USDGBP" and place them in the prices dictionary.
|
"USDGBP" and place them in the prices dictionary.
|
||||||
"""
|
"""
|
||||||
|
getcontext().rounding = ROUND_HALF_DOWN
|
||||||
inv_pair = "%s%s" % (pair[3:], pair[:3])
|
inv_pair = "%s%s" % (pair[3:], pair[:3])
|
||||||
inv_bid = (Decimal("1.0")/bid).quantize(
|
inv_bid = (Decimal("1.0")/bid).quantize(
|
||||||
Decimal("0.00001", ROUND_HALF_DOWN)
|
Decimal("0.00001")
|
||||||
)
|
)
|
||||||
inv_ask = (Decimal("1.0")/ask).quantize(
|
inv_ask = (Decimal("1.0")/ask).quantize(
|
||||||
Decimal("0.00001", ROUND_HALF_DOWN)
|
Decimal("0.00001")
|
||||||
)
|
)
|
||||||
return inv_pair, inv_bid, inv_ask
|
return inv_pair, inv_bid, inv_ask
|
||||||
|
|
||||||
def connect_to_stream(self):
|
def connect_to_stream(self):
|
||||||
pairs_oanda = ["%s_%s" % (p[:3], p[3:]) for p in self.pairs]
|
pairs_oanda = ["%s_%s" % (p[:3], p[3:]) for p in self.pairs]
|
||||||
try:
|
try:
|
||||||
|
requests.packages.urllib3.disable_warnings()
|
||||||
s = requests.Session()
|
s = requests.Session()
|
||||||
url = "https://" + self.domain + "/v1/prices"
|
url = "https://" + self.domain + "/v1/prices"
|
||||||
headers = {'Authorization' : 'Bearer ' + self.access_token}
|
headers = {'Authorization' : 'Bearer ' + self.access_token}
|
||||||
@@ -46,7 +50,7 @@ class StreamingForexPrices(PriceHandler):
|
|||||||
return resp
|
return resp
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
s.close()
|
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):
|
def stream_to_queue(self):
|
||||||
response = self.connect_to_stream()
|
response = self.connect_to_stream()
|
||||||
@@ -55,19 +59,21 @@ class StreamingForexPrices(PriceHandler):
|
|||||||
for line in response.iter_lines(1):
|
for line in response.iter_lines(1):
|
||||||
if line:
|
if line:
|
||||||
try:
|
try:
|
||||||
msg = json.loads(line)
|
dline = line.decode('utf-8')
|
||||||
|
msg = json.loads(dline)
|
||||||
except Exception as e:
|
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
|
return
|
||||||
if msg.has_key("instrument") or msg.has_key("tick"):
|
if "instrument" in msg or "tick" in msg:
|
||||||
print msg
|
print(msg)
|
||||||
|
getcontext().rounding = ROUND_HALF_DOWN
|
||||||
instrument = msg["tick"]["instrument"].replace("_", "")
|
instrument = msg["tick"]["instrument"].replace("_", "")
|
||||||
time = msg["tick"]["time"]
|
time = msg["tick"]["time"]
|
||||||
bid = Decimal(str(msg["tick"]["bid"])).quantize(
|
bid = Decimal(str(msg["tick"]["bid"])).quantize(
|
||||||
Decimal("0.00001", ROUND_HALF_DOWN)
|
Decimal("0.00001")
|
||||||
)
|
)
|
||||||
ask = Decimal(str(msg["tick"]["ask"])).quantize(
|
ask = Decimal(str(msg["tick"]["ask"])).quantize(
|
||||||
Decimal("0.00001", ROUND_HALF_DOWN)
|
Decimal("0.00001")
|
||||||
)
|
)
|
||||||
self.prices[instrument]["bid"] = bid
|
self.prices[instrument]["bid"] = bid
|
||||||
self.prices[instrument]["ask"] = ask
|
self.prices[instrument]["ask"] = ask
|
||||||
|
|||||||
+14
-4
@@ -1,6 +1,16 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
import httplib
|
try:
|
||||||
import urllib
|
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):
|
class ExecutionHandler(object):
|
||||||
@@ -47,7 +57,7 @@ class OANDAExecutionHandler(ExecutionHandler):
|
|||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
"Authorization": "Bearer " + self.access_token
|
"Authorization": "Bearer " + self.access_token
|
||||||
}
|
}
|
||||||
params = urllib.urlencode({
|
params = urlencode({
|
||||||
"instrument" : instrument,
|
"instrument" : instrument,
|
||||||
"units" : event.units,
|
"units" : event.units,
|
||||||
"type" : event.order_type,
|
"type" : event.order_type,
|
||||||
@@ -59,5 +69,5 @@ class OANDAExecutionHandler(ExecutionHandler):
|
|||||||
params, headers
|
params, headers
|
||||||
)
|
)
|
||||||
response = self.conn.getresponse().read()
|
response = self.conn.getresponse().read()
|
||||||
print response
|
print(response)
|
||||||
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from decimal import Decimal, getcontext, ROUND_HALF_DOWN
|
from decimal import Decimal, getcontext, ROUND_HALF_DOWN
|
||||||
import os
|
import os
|
||||||
@@ -73,7 +75,7 @@ class Portfolio(object):
|
|||||||
out_file = os.path.join(OUTPUT_RESULTS_DIR, filename)
|
out_file = os.path.join(OUTPUT_RESULTS_DIR, filename)
|
||||||
df_equity = pd.DataFrame.from_records(self.equity, index='time')
|
df_equity = pd.DataFrame.from_records(self.equity, index='time')
|
||||||
df_equity.to_csv(out_file)
|
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):
|
def execute_signal(self, signal_event):
|
||||||
side = signal_event.side
|
side = signal_event.side
|
||||||
@@ -123,5 +125,6 @@ class Portfolio(object):
|
|||||||
order = OrderEvent(currency_pair, units, "market", side)
|
order = OrderEvent(currency_pair, units, "market", side)
|
||||||
self.events.put(order)
|
self.events.put(order)
|
||||||
|
|
||||||
print "Balance: %0.2f" % self.balance
|
print("Balance: %0.2f" % self.balance)
|
||||||
self.append_equity_row(time, self.balance)
|
self.append_equity_row(time, self.balance)
|
||||||
|
|
||||||
@@ -92,7 +92,8 @@ class Position(object):
|
|||||||
self.update_position_price()
|
self.update_position_price()
|
||||||
# Calculate PnL
|
# Calculate PnL
|
||||||
pnl = self.calculate_pips() * qh_close * dec_units
|
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):
|
def close_position(self):
|
||||||
ticker_cp = self.ticker.prices[self.currency_pair]
|
ticker_cp = self.ticker.prices[self.currency_pair]
|
||||||
@@ -106,4 +107,5 @@ class Position(object):
|
|||||||
self.update_position_price()
|
self.update_position_price()
|
||||||
# Calculate PnL
|
# Calculate PnL
|
||||||
pnl = self.calculate_pips() * qh_close * self.units
|
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"))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from decimal import Decimal, getcontext
|
from decimal import Decimal
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from position import Position
|
from position import Position
|
||||||
@@ -28,7 +28,6 @@ class TestLongGBPUSDPosition(unittest.TestCase):
|
|||||||
denominated currency of GBP, using 2,000 units of GBP/USD.
|
denominated currency of GBP, using 2,000 units of GBP/USD.
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
getcontext.prec = 2
|
|
||||||
home_currency = "GBP"
|
home_currency = "GBP"
|
||||||
position_type = "long"
|
position_type = "long"
|
||||||
currency_pair = "GBPUSD"
|
currency_pair = "GBPUSD"
|
||||||
@@ -78,7 +77,6 @@ class TestShortGBPUSDPosition(unittest.TestCase):
|
|||||||
denominated currency of GBP, using 2,000 units of GBP/USD.
|
denominated currency of GBP, using 2,000 units of GBP/USD.
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
getcontext.prec = 2
|
|
||||||
home_currency = "GBP"
|
home_currency = "GBP"
|
||||||
position_type = "short"
|
position_type = "short"
|
||||||
currency_pair = "GBPUSD"
|
currency_pair = "GBPUSD"
|
||||||
@@ -132,7 +130,6 @@ class TestLongEURUSDPosition(unittest.TestCase):
|
|||||||
denominated currency of GBP, using 2,000 units of EUR/USD.
|
denominated currency of GBP, using 2,000 units of EUR/USD.
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
getcontext.prec = 2
|
|
||||||
home_currency = "GBP"
|
home_currency = "GBP"
|
||||||
position_type = "long"
|
position_type = "long"
|
||||||
currency_pair = "EURUSD"
|
currency_pair = "EURUSD"
|
||||||
@@ -183,7 +180,6 @@ class TestLongEURUSDPosition(unittest.TestCase):
|
|||||||
denominated currency of GBP, using 2,000 units of EUR/USD.
|
denominated currency of GBP, using 2,000 units of EUR/USD.
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
getcontext.prec = 2
|
|
||||||
home_currency = "GBP"
|
home_currency = "GBP"
|
||||||
position_type = "short"
|
position_type = "short"
|
||||||
currency_pair = "EURUSD"
|
currency_pair = "EURUSD"
|
||||||
|
|||||||
+7
-4
@@ -1,8 +1,11 @@
|
|||||||
import copy
|
import copy
|
||||||
import Queue
|
from decimal import Decimal, getcontext
|
||||||
|
try:
|
||||||
|
import Queue as queue
|
||||||
|
except ImportError:
|
||||||
|
import queue
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from decimal import Decimal, getcontext
|
|
||||||
|
|
||||||
from qsforex.execution.execution import OANDAExecutionHandler
|
from qsforex.execution.execution import OANDAExecutionHandler
|
||||||
from qsforex.portfolio.portfolio import Portfolio
|
from qsforex.portfolio.portfolio import Portfolio
|
||||||
@@ -22,7 +25,7 @@ def trade(events, strategy, portfolio, execution, heartbeat):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
event = events.get(False)
|
event = events.get(False)
|
||||||
except Queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if event is not None:
|
if event is not None:
|
||||||
@@ -40,7 +43,7 @@ if __name__ == "__main__":
|
|||||||
getcontext().prec = 2
|
getcontext().prec = 2
|
||||||
|
|
||||||
heartbeat = 0.0 # Half a second between polling
|
heartbeat = 0.0 # Half a second between polling
|
||||||
events = Queue.Queue()
|
events = queue.Queue()
|
||||||
equity = settings.EQUITY
|
equity = settings.EQUITY
|
||||||
|
|
||||||
# Trade "Cable"
|
# Trade "Cable"
|
||||||
|
|||||||
Reference in New Issue
Block a user