diff --git a/data/streaming.py b/data/streaming.py index fed07ea..1ec77e5 100644 --- a/data/streaming.py +++ b/data/streaming.py @@ -38,12 +38,13 @@ class StreamingForexPrices(PriceHandler): 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' : pairs_oanda, 'accountId' : self.account_id} + 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) diff --git a/portfolio/portfolio.py b/portfolio/portfolio.py index faa14ed..9c7dd5e 100644 --- a/portfolio/portfolio.py +++ b/portfolio/portfolio.py @@ -126,51 +126,65 @@ class Portfolio(object): print(out_line[:-2]) self.backtest_file.write(out_line) - def execute_signal(self, signal_event): - side = signal_event.side - currency_pair = signal_event.instrument - units = int(self.trade_units) - time = signal_event.time - - # If there is no position, create one - if currency_pair not in self.positions: - if side == "buy": - position_type = "long" + def execute_signal(self, signal_event): + # Check that the prices ticker contains all necessary + # currency pairs prior to executing an order + execute = True + tp = self.ticker.prices + for pair in tp: + if tp[pair]["ask"] is None or tp[pair]["bid"] is None: + execute = False + + # All necessary pricing data is available, + # we can execute + if execute: + side = signal_event.side + currency_pair = signal_event.instrument + units = int(self.trade_units) + time = signal_event.time + + # If there is no position, create one + if currency_pair not in self.positions: + if side == "buy": + position_type = "long" + else: + position_type = "short" + self.add_new_position( + position_type, currency_pair, + units, self.ticker + ) + + # If a position exists add or remove units else: - position_type = "short" - self.add_new_position( - position_type, currency_pair, - units, self.ticker - ) + ps = self.positions[currency_pair] - # If a position exists add or remove units + if side == "buy" and ps.position_type == "long": + add_position_units(currency_pair, units) + + elif side == "sell" and ps.position_type == "long": + if units == ps.units: + self.close_position(currency_pair) + # TODO: Allow units to be added/removed + elif units < ps.units: + return + elif units > ps.units: + return + + elif side == "buy" and ps.position_type == "short": + if units == ps.units: + self.close_position(currency_pair) + # TODO: Allow units to be added/removed + elif units < ps.units: + return + elif units > ps.units: + return + + elif side == "sell" and ps.position_type == "short": + add_position_units(currency_pair, units) + + order = OrderEvent(currency_pair, units, "market", side) + self.events.put(order) + print("Balance: ", self.balance) else: - ps = self.positions[currency_pair] - - if side == "buy" and ps.position_type == "long": - add_position_units(currency_pair, units) - - elif side == "sell" and ps.position_type == "long": - if units == ps.units: - self.close_position(currency_pair) - # TODO: Allow units to be added/removed - elif units < ps.units: - return - elif units > ps.units: - return - - elif side == "buy" and ps.position_type == "short": - if units == ps.units: - self.close_position(currency_pair) - # TODO: Allow units to be added/removed - elif units < ps.units: - return - elif units > ps.units: - return - - elif side == "sell" and ps.position_type == "short": - add_position_units(currency_pair, units) - - order = OrderEvent(currency_pair, units, "market", side) - self.events.put(order) + print("Unable to execute order as price data was insufficient.") \ No newline at end of file diff --git a/portfolio/portfolio_test.py b/portfolio/portfolio_test.py index 6c8d939..e6b8602 100644 --- a/portfolio/portfolio_test.py +++ b/portfolio/portfolio_test.py @@ -212,7 +212,7 @@ class TestPortfolio(unittest.TestCase): ) self.assertTrue(rpu) self.assertEqual(ps.units, Decimal("7000")) - self.assertEqual(self.port.balance, Decimal("99988.84")) + self.assertEqual(self.port.balance, Decimal("99988.83")) def test_close_position_long(self): position_type = "long" @@ -265,7 +265,7 @@ class TestPortfolio(unittest.TestCase): cp = self.port.close_position(currency_pair) self.assertTrue(cp) self.assertRaises(ps) # Key doesn't exist - self.assertEqual(self.port.balance, Decimal("100026.64")) + self.assertEqual(self.port.balance, Decimal("100026.63")) def test_close_position_short(self): position_type = "short" @@ -312,13 +312,13 @@ class TestPortfolio(unittest.TestCase): ) self.assertTrue(rpu) self.assertEqual(ps.units, Decimal("7000")) - self.assertEqual(self.port.balance, Decimal("99988.84")) + self.assertEqual(self.port.balance, Decimal("99988.83")) # Close the position cp = self.port.close_position(currency_pair) self.assertTrue(cp) self.assertRaises(ps) # Key doesn't exist - self.assertEqual(self.port.balance, Decimal("99962.80")) + self.assertEqual(self.port.balance, Decimal("99962.77")) if __name__ == "__main__": diff --git a/portfolio/position.py b/portfolio/position.py index f2fc385..def814b 100644 --- a/portfolio/position.py +++ b/portfolio/position.py @@ -24,7 +24,7 @@ class Position(object): ticker_cur = self.ticker.prices[self.currency_pair] if self.position_type == "long": self.avg_price = Decimal(str(ticker_cur["ask"])) - self.cur_price = Decimal(str(ticker_cur["bid"])) + self.cur_price = Decimal(str(ticker_cur["bid"])) else: self.avg_price = Decimal(str(ticker_cur["bid"])) self.cur_price = Decimal(str(ticker_cur["ask"])) @@ -83,11 +83,11 @@ class Position(object): ticker_cp = self.ticker.prices[self.currency_pair] ticker_qh = self.ticker.prices[self.quote_home_currency_pair] if self.position_type == "long": - remove_price = ticker_cp["ask"] - qh_close = ticker_qh["bid"] - else: remove_price = ticker_cp["bid"] qh_close = ticker_qh["ask"] + else: + remove_price = ticker_cp["ask"] + qh_close = ticker_qh["bid"] self.units -= dec_units self.update_position_price() # Calculate PnL @@ -99,11 +99,9 @@ class Position(object): ticker_cp = self.ticker.prices[self.currency_pair] ticker_qh = self.ticker.prices[self.quote_home_currency_pair] if self.position_type == "long": - remove_price = ticker_cp["ask"] - qh_close = ticker_qh["bid"] - else: - remove_price = ticker_cp["bid"] qh_close = ticker_qh["ask"] + else: + qh_close = ticker_qh["bid"] self.update_position_price() # Calculate PnL pnl = self.calculate_pips() * qh_close * self.units diff --git a/strategy/strategy.py b/strategy/strategy.py index 0c1f874..248e592 100644 --- a/strategy/strategy.py +++ b/strategy/strategy.py @@ -20,7 +20,7 @@ class TestStrategy(object): self.invested = False def calculate_signals(self, event): - if event.type == 'TICK': + if event.type == 'TICK' and event.instrument == self.pairs[0]: if self.ticks % 5 == 0: if self.invested == False: signal = SignalEvent(self.pairs[0], "market", "buy", event.time) diff --git a/trading/trading.py b/trading/trading.py index c2e9b79..359542d 100644 --- a/trading/trading.py +++ b/trading/trading.py @@ -47,8 +47,8 @@ if __name__ == "__main__": events = queue.Queue() equity = settings.EQUITY - # Trade "Cable" - pairs = ["GBPUSD"] + # Pairs to include in streaming data set + pairs = ["EURUSD", "GBPUSD"] # Create the OANDA market price streaming class # making sure to provide authentication commands