def test_pcm_fixed_weight_optimiser_fixed_alpha_weights_call_end_to_end( helpers): """ Tests the full portfolio base class logic for carrying out rebalancing. TODO: DataHandler is mocked. A non-disk based data source should be utilised instead. """ first_dt = pd.Timestamp('2019-01-01 15:00:00', tz=pytz.utc) asset_list = ['EQ:SPY', 'EQ:AGG', 'EQ:TLT', 'EQ:GLD'] initial_funds = 1e6 account_id = '1234' port_id = '1234' cash_buffer_perc = 0.05 exchange = SimulatedExchange(first_dt) universe = StaticUniverse(asset_list) mock_asset_prices_first = { 'EQ:SPY': 56.87, 'EQ:AGG': 219.45, 'EQ:TLT': 178.33, 'EQ:GLD': 534.21 } data_handler = Mock() data_handler.get_asset_latest_ask_price.side_effect = \ lambda self, x: mock_asset_prices_first[x] broker = SimulatedBroker(first_dt, exchange, data_handler, account_id, initial_funds=initial_funds) broker.create_portfolio(port_id, 'Portfolio') broker.subscribe_funds_to_portfolio(port_id, initial_funds) order_sizer = DollarWeightedCashBufferedOrderSizeGeneration( broker, port_id, data_handler, cash_buffer_perc) optimiser = FixedWeightPortfolioOptimiser(data_handler) alpha_weights = { 'EQ:SPY': 0.345, 'EQ:AGG': 0.611, 'EQ:TLT': 0.870, 'EQ:GLD': 0.0765 } alpha_model = FixedSignalsAlphaModel(alpha_weights) pcm = PortfolioConstructionModel(broker, port_id, universe, order_sizer, optimiser, alpha_model) result_first = pcm(first_dt) expected_first = [ Order(first_dt, 'EQ:AGG', 1390), Order(first_dt, 'EQ:GLD', 71), Order(first_dt, 'EQ:SPY', 3029), Order(first_dt, 'EQ:TLT', 2436) ] helpers.assert_order_lists_equal(result_first, expected_first)
def test_withdraw_funds_from_portfolio(): """ Tests withdraw_funds_from_portfolio method for: * Raising ValueError with negative amount * Raising ValueError if portfolio does not exist * Raising ValueError for a lack of cash * Correctly setting cash_balances for a positive amount """ start_dt = pd.Timestamp('2017-10-05 08:00:00', tz=pytz.UTC) exchange = ExchangeMock() data_handler = DataHandlerMock() sb = SimulatedBroker(start_dt, exchange, data_handler) # Raising ValueError with negative amount with pytest.raises(ValueError): sb.withdraw_funds_from_portfolio("1234", -4306.23) # Raising KeyError if portfolio doesn't exist with pytest.raises(KeyError): sb.withdraw_funds_from_portfolio("1234", 5432.12) # Add in cash balance to the account sb.create_portfolio(portfolio_id=1234, name="My Portfolio #1") sb.subscribe_funds_to_account(165303.23) sb.subscribe_funds_to_portfolio("1234", 100000.00) # Raising ValueError if not enough cash with pytest.raises(ValueError): sb.withdraw_funds_from_portfolio("1234", 200000.00) # If everything else worked, check balances are correct sb.withdraw_funds_from_portfolio("1234", 50000.00) assert sb.cash_balances[sb.base_currency] == 115303.23000000001 assert sb.portfolios["1234"].total_cash == 50000.00
def test_get_account_total_market_value(): """ Tests get_account_total_market_value method for: * The correct market values after cash is subscribed. """ start_dt = pd.Timestamp('2017-10-05 08:00:00', tz=pytz.UTC) exchange = ExchangeMock() data_handler = DataHandlerMock() sb = SimulatedBroker(start_dt, exchange, data_handler) # Subscribe all necessary funds and create portfolios sb.subscribe_funds_to_account(300000.0) sb.create_portfolio(portfolio_id="1", name="My Portfolio #1") sb.create_portfolio(portfolio_id="2", name="My Portfolio #1") sb.create_portfolio(portfolio_id="3", name="My Portfolio #1") sb.subscribe_funds_to_portfolio("1", 100000.0) sb.subscribe_funds_to_portfolio("2", 100000.0) sb.subscribe_funds_to_portfolio("3", 100000.0) # Check that the market value is correct res_equity = sb.get_account_total_equity() test_equity = { "1": 100000.0, "2": 100000.0, "3": 100000.0, "master": 300000.0 } assert res_equity == test_equity
def _create_broker(self): """ Create the SimulatedBroker with an appropriate default portfolio identifiers. Returns ------- `SimulatedBroker` The simulated broker instance. """ broker = SimulatedBroker(self.start_dt, self.exchange, self.data_handler, account_id=self.account_name, initial_funds=self.initial_cash, fee_model=self.fee_model) broker.create_portfolio(self.portfolio_id, self.portfolio_name) broker.subscribe_funds_to_portfolio(self.portfolio_id, self.initial_cash) return broker
def test_get_portfolio_non_cash_equity(): """ Tests get_portfolio_non_cash_equity method for: * Raising ValueError if portfolio_id not in keys * Correctly obtaining the market value after cash transfers """ start_dt = pd.Timestamp('2017-10-05 08:00:00', tz=pytz.UTC) exchange = ExchangeMock() data_handler = DataHandlerMock() sb = SimulatedBroker(start_dt, exchange, data_handler) # Raising KeyError if portfolio_id not in keys with pytest.raises(KeyError): sb.get_portfolio_non_cash_equity("5678") # Create fund transfers and portfolio sb.create_portfolio(portfolio_id=1234, name="My Portfolio #1") sb.subscribe_funds_to_account(175000.0) sb.subscribe_funds_to_portfolio("1234", 100000.00) # Check correct values obtained after cash transfers assert sb.get_portfolio_total_equity("1234") == 100000.0
def test_submit_order(): """ Tests the execute_order method for: * Raises ValueError if no portfolio_id * Raises ValueError if bid/ask is (np.NaN, np.NaN) * Checks that bid/ask are correctly set dependent upon order direction * Checks that portfolio values are correct after carrying out a transaction """ start_dt = pd.Timestamp('2017-10-05 08:00:00', tz=pytz.UTC) # Raising KeyError if portfolio_id not in keys exchange = ExchangeMock() data_handler = DataHandlerMock() sb = SimulatedBroker(start_dt, exchange, data_handler) asset = AssetMock("Royal Dutch Shell Class B", "EQ:RDSB") quantity = 100 order = OrderMock(asset.symbol, quantity) with pytest.raises(KeyError): sb.submit_order("1234", order) # Raises ValueError if bid/ask is (np.NaN, np.NaN) exchange_exception = ExchangeMockException() sbnp = SimulatedBroker(start_dt, exchange_exception, data_handler) sbnp.create_portfolio(portfolio_id=1234, name="My Portfolio #1") quantity = 100 order = OrderMock(asset.symbol, quantity) with pytest.raises(ValueError): sbnp._execute_order(start_dt, "1234", order) # Checks that bid/ask are correctly set dependent on # order direction # Positive direction exchange_price = ExchangeMockPrice() data_handler_price = DataHandlerMockPrice() sbwp = SimulatedBroker(start_dt, exchange_price, data_handler_price) sbwp.create_portfolio(portfolio_id=1234, name="My Portfolio #1") sbwp.subscribe_funds_to_account(175000.0) sbwp.subscribe_funds_to_portfolio("1234", 100000.00) quantity = 1000 order = OrderMock(asset.symbol, quantity) sbwp.submit_order("1234", order) sbwp.update(start_dt) port = sbwp.portfolios["1234"] assert port.total_cash == 46530.0 assert port.total_non_cash_equity == 53470.0 assert port.total_equity == 100000.0 assert port.pos_handler.positions[asset.symbol].book_cost == 53470.0 assert port.pos_handler.positions[asset.symbol].unrealised_gain == 0.0 assert port.pos_handler.positions[asset.symbol].market_value == 53470.0 assert port.pos_handler.positions[asset.symbol].unrealised_percentage_gain == 0.0 assert port.pos_handler.positions[asset.symbol].quantity == 1000 # Negative direction exchange_price = ExchangeMockPrice() sbwp = SimulatedBroker(start_dt, exchange_price, data_handler_price) sbwp.create_portfolio(portfolio_id=1234, name="My Portfolio #1") sbwp.subscribe_funds_to_account(175000.0) sbwp.subscribe_funds_to_portfolio("1234", 100000.00) quantity = -1000 order = OrderMock(asset.symbol, quantity) sbwp.submit_order("1234", order) sbwp.update(start_dt) port = sbwp.portfolios["1234"] assert port.total_cash == 153450.0 assert port.total_non_cash_equity == -53450.0 assert port.total_equity == 100000.0 assert port.pos_handler.positions[asset.symbol].book_cost == -53450.0 assert port.pos_handler.positions[asset.symbol].unrealised_gain == 0.0 assert port.pos_handler.positions[asset.symbol].market_value == -53450.0 assert port.pos_handler.positions[asset.symbol].unrealised_percentage_gain == 0.0 assert port.pos_handler.positions[asset.symbol].quantity == -1000