From 8c77f6ba822bfd6bd23ee2ce65bb7049a535a0a9 Mon Sep 17 00:00:00 2001 From: Kennedy Mbuthia Date: Tue, 12 Jul 2016 22:55:53 +0300 Subject: [PATCH 01/10] event: event object has the comparison operator for two different events; adding time attribute to order event; describing different priority values for the different events --- event/event.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/event/event.py b/event/event.py index 0a7c118..7706b83 100644 --- a/event/event.py +++ b/event/event.py @@ -1,9 +1,16 @@ +from datetime import datetime + + class Event(object): - pass + def __lt__(self, other): + return self.time < other.time class TickEvent(Event): def __init__(self, instrument, time, bid, ask): + ''' + This will have priority value of 30 + ''' self.type = 'TICK' self.instrument = instrument self.time = time @@ -21,6 +28,10 @@ def __repr__(self): class SignalEvent(Event): + ''' + This will have priority value of 20 for buy event + This will have priority value of 20 for sell event + ''' def __init__(self, instrument, order_type, side, time): self.type = 'SIGNAL' self.instrument = instrument @@ -39,12 +50,16 @@ def __repr__(self): class OrderEvent(Event): + ''' + This will have priority value of 10 + ''' def __init__(self, instrument, units, order_type, side): self.type = 'ORDER' self.instrument = instrument self.units = units self.order_type = order_type self.side = side + self.time = datetime.now() def __str__(self): return "Type: %s, Instrument: %s, Units: %s, Order Type: %s, Side: %s" % ( @@ -53,4 +68,4 @@ def __str__(self): ) def __repr__(self): - return str(self) \ No newline at end of file + return str(self) From 26ed91ad00fda0e372e34504c40d8233698dc067 Mon Sep 17 00:00:00 2001 From: Kennedy Mbuthia Date: Tue, 12 Jul 2016 22:57:33 +0300 Subject: [PATCH 02/10] streaming: modifying the tick event with the appropriate priority value for the queue --- data/streaming.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/streaming.py b/data/streaming.py index 3abe7dd..8142fc9 100644 --- a/data/streaming.py +++ b/data/streaming.py @@ -89,4 +89,4 @@ def stream_to_queue(self): self.prices[inv_pair]["ask"] = inv_ask self.prices[inv_pair]["time"] = time tev = TickEvent(instrument, time, bid, ask) - self.events_queue.put(tev) + self.events_queue.put((50, tev)) From 29f10bc79fcb822ae1d189e5ba5d6e3f3581e3ee Mon Sep 17 00:00:00 2001 From: Kennedy Mbuthia Date: Tue, 12 Jul 2016 22:59:47 +0300 Subject: [PATCH 03/10] trading: changing events to Priority queue and changing the event to be extracted from the tuple of the events queue --- trading/trading.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/trading/trading.py b/trading/trading.py index e418896..6ce3133 100644 --- a/trading/trading.py +++ b/trading/trading.py @@ -31,16 +31,16 @@ def trade(events, strategy, portfolio, execution, heartbeat): pass else: if event is not None: - if event.type == 'TICK': - logger.info("Received new tick event: %s", event) - strategy.calculate_signals(event) - portfolio.update_portfolio(event) - elif event.type == 'SIGNAL': - logger.info("Received new signal event: %s", event) - portfolio.execute_signal(event) - elif event.type == 'ORDER': - logger.info("Received new order event: %s", event) - execution.execute_order(event) + if event[1].type == 'TICK': + logger.info("Received new tick event: %s", event[1]) + strategy.calculate_signals(event[1]) + portfolio.update_portfolio(event[1]) + elif event[1].type == 'SIGNAL': + logger.info("Received new signal event: %s", event[1]) + portfolio.execute_signal(event[1]) + elif event[1].type == 'ORDER': + logger.info("Received new order event: %s", event[1]) + execution.execute_order(event[1]) time.sleep(heartbeat) @@ -53,7 +53,7 @@ def trade(events, strategy, portfolio, execution, heartbeat): getcontext().prec = 2 heartbeat = 0.0 # Time in seconds between polling - events = queue.Queue() + events = queue.PriorityQueue() equity = settings.EQUITY # Pairs to include in streaming data set From 0f9bc53f53f63fd297e3eb4ad5f7c2f35e196c59 Mon Sep 17 00:00:00 2001 From: Kennedy Mbuthia Date: Tue, 12 Jul 2016 23:00:59 +0300 Subject: [PATCH 04/10] strategy: adding correct priority for test strategy --- strategy/strategy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/strategy/strategy.py b/strategy/strategy.py index 248e592..f2351fd 100644 --- a/strategy/strategy.py +++ b/strategy/strategy.py @@ -24,11 +24,11 @@ def calculate_signals(self, event): if self.ticks % 5 == 0: if self.invested == False: signal = SignalEvent(self.pairs[0], "market", "buy", event.time) - self.events.put(signal) + self.events.put((20, signal)) self.invested = True else: signal = SignalEvent(self.pairs[0], "market", "sell", event.time) - self.events.put(signal) + self.events.put((20, signal)) self.invested = False self.ticks += 1 @@ -99,4 +99,4 @@ def calculate_signals(self, event): signal = SignalEvent(pair, "market", "sell", event.time) self.events.put(signal) pd["invested"] = False - pd["ticks"] += 1 \ No newline at end of file + pd["ticks"] += 1 From da1c117936a2a8ba4225cac6fbdb865f9f375f9f Mon Sep 17 00:00:00 2001 From: Kennedy Mbuthia Date: Tue, 12 Jul 2016 23:02:25 +0300 Subject: [PATCH 05/10] portfolio: changing the event to have the right priority --- portfolio/portfolio.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/portfolio/portfolio.py b/portfolio/portfolio.py index c86aafb..6acad15 100644 --- a/portfolio/portfolio.py +++ b/portfolio/portfolio.py @@ -185,9 +185,8 @@ def execute_signal(self, signal_event): add_position_units(currency_pair, units) order = OrderEvent(currency_pair, units, "market", side) - self.events.put(order) + self.events.put((10, order)) self.logger.info("Portfolio Balance: %s" % self.balance) else: self.logger.info("Unable to execute order as price data was insufficient.") - \ No newline at end of file From 3cfb29bfedbc13d5fbb2e9305e1fa9c130cb72e7 Mon Sep 17 00:00:00 2001 From: Kennedy Mbuthia Date: Wed, 13 Jul 2016 12:24:16 +0300 Subject: [PATCH 06/10] logging: adding file handler --- logging.conf | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/logging.conf b/logging.conf index ee8ec95..0360736 100644 --- a/logging.conf +++ b/logging.conf @@ -2,27 +2,33 @@ keys=root,qsforex.trading.trading [handlers] -keys=consoleHandler +keys=consoleHandler, fileHandler [formatters] keys=simpleFormatter [logger_root] level=DEBUG -handlers=consoleHandler +handlers=consoleHandler,fileHandler [logger_qsforex.trading.trading] level=DEBUG -handlers=consoleHandler +handlers=consoleHandler,fileHandler qualname=qsforex.trading.trading propagate=0 [handler_consoleHandler] class=StreamHandler -level=DEBUG +level=INFO formatter=simpleFormatter args=(sys.stdout,) +[handler_fileHandler] +class=FileHandler +level=DEBUG +formatter=simpleFormatter +args=("output.log",) + [formatter_simpleFormatter] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s datefmt= From d17698c621a65a9b52e0ddd1962cd597c3978117 Mon Sep 17 00:00:00 2001 From: Kennedy Mbuthia Date: Wed, 13 Jul 2016 12:25:27 +0300 Subject: [PATCH 07/10] price: pandas V.18 -header accepts int not bool --- data/price.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/price.py b/data/price.py index ec0d32c..4d0018b 100644 --- a/data/price.py +++ b/data/price.py @@ -138,7 +138,7 @@ def _open_convert_csv_files_for_day(self, date_str): for p in self.pairs: pair_path = os.path.join(self.csv_dir, '%s_%s.csv' % (p, date_str)) self.pair_frames[p] = pd.io.parsers.read_csv( - pair_path, header=True, index_col=0, + pair_path, header=0, index_col=0, parse_dates=True, dayfirst=True, names=("Time", "Ask", "Bid", "AskVolume", "BidVolume") ) From fcb101b6805205d6f5c23c60c8b9c30723a1fa03 Mon Sep 17 00:00:00 2001 From: Kennedy Mbuthia Date: Wed, 13 Jul 2016 12:26:41 +0300 Subject: [PATCH 08/10] mac: removed newline at end of file --- examples/mac.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mac.py b/examples/mac.py index 6ebed7f..355b129 100644 --- a/examples/mac.py +++ b/examples/mac.py @@ -26,4 +26,4 @@ Portfolio, SimulatedExecution, equity=settings.EQUITY ) - backtest.simulate_trading() \ No newline at end of file + backtest.simulate_trading() From 193d1b120610769f6b22f7466d7e822b41ebc8a6 Mon Sep 17 00:00:00 2001 From: Kennedy Mbuthia Date: Wed, 13 Jul 2016 22:53:21 +0300 Subject: [PATCH 09/10] price: adding events queue --- data/price.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/price.py b/data/price.py index 4d0018b..ecaa59d 100644 --- a/data/price.py +++ b/data/price.py @@ -199,4 +199,4 @@ def stream_next_tick(self): # Create the tick event for the queue tev = TickEvent(pair, index, bid, ask) - self.events_queue.put(tev) + self.events_queue.put((30, tev)) From 1e550a47a270dea9a313472f0ad931ef864db2ff Mon Sep 17 00:00:00 2001 From: Kennedy Mbuthia Date: Wed, 13 Jul 2016 22:54:29 +0300 Subject: [PATCH 10/10] backtest: adding priority queue --- backtest/backtest.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/backtest/backtest.py b/backtest/backtest.py index 249405c..bceba15 100644 --- a/backtest/backtest.py +++ b/backtest/backtest.py @@ -23,8 +23,9 @@ def __init__( """ Initialises the backtest. """ + import ipdb; ipdb.set_trace() self.pairs = pairs - self.events = queue.Queue() + self.events = queue.PriorityQueue() self.csv_dir = settings.CSV_DATA_DIR self.ticker = data_handler(self.pairs, self.events, self.csv_dir) self.strategy_params = strategy_params @@ -57,13 +58,13 @@ def _run_backtest(self): self.ticker.stream_next_tick() else: if event is not None: - if event.type == 'TICK': - self.strategy.calculate_signals(event) - self.portfolio.update_portfolio(event) - elif event.type == 'SIGNAL': - self.portfolio.execute_signal(event) - elif event.type == 'ORDER': - self.execution.execute_order(event) + if event[1].type == 'TICK': + self.strategy.calculate_signals(event[1]) + self.portfolio.update_portfolio(event[1]) + elif event[1].type == 'SIGNAL': + self.portfolio.execute_signal(event[1]) + elif event[1].type == 'ORDER': + self.execution.execute_order(event[1]) time.sleep(self.heartbeat) iters += 1