Ejemplo n.º 1
0
def test_all_cases_of_set_broker_commission():
    """
    Tests that _set_broker_commission correctly sets the
    appropriate broker commission model depending upon
    user choice.
    """
    start_dt = pd.Timestamp('2017-10-05 08:00:00', tz=pytz.UTC)
    exchange = ExchangeMock()
    data_handler = DataHandlerMock()

    # Broker commission is None
    sb1 = SimulatedBroker(start_dt, exchange, data_handler)
    assert sb1.fee_model.__class__.__name__ == "ZeroFeeModel"

    # Broker commission is specified as a subclass
    # of FeeModel abstract base class
    bc2 = ZeroFeeModel()
    sb2 = SimulatedBroker(
        start_dt, exchange, data_handler, fee_model=bc2
    )
    assert sb2.fee_model.__class__.__name__ == "ZeroFeeModel"

    # FeeModel is mis-specified and thus
    # raises a TypeError
    with pytest.raises(TypeError):
        SimulatedBroker(
            start_dt, exchange, data_handler, fee_model="bad_fee_model"
        )
Ejemplo n.º 2
0
def test_initial_settings_for_default_simulated_broker():
    """
    Tests that the SimulatedBroker settings are set
    correctly for default settings.
    """
    start_dt = pd.Timestamp('2017-10-05 08:00:00', tz=pytz.UTC)
    exchange = ExchangeMock()
    data_handler = DataHandlerMock()

    # Test a default SimulatedBroker
    sb1 = SimulatedBroker(start_dt, exchange, data_handler)

    assert sb1.start_dt == start_dt
    assert sb1.current_dt == start_dt
    assert sb1.exchange == exchange
    assert sb1.account_id is None
    assert sb1.base_currency == "USD"
    assert sb1.initial_funds == 0.0
    assert type(sb1.fee_model) == ZeroFeeModel

    tcb1 = dict(
        zip(
            settings.SUPPORTED['CURRENCIES'],
            [0.0] * len(settings.SUPPORTED['CURRENCIES'])
        )
    )

    assert sb1.cash_balances == tcb1
    assert sb1.portfolios == {}
    assert sb1.open_orders == {}

    # Test a SimulatedBroker with some parameters set
    sb2 = SimulatedBroker(
        start_dt, exchange, data_handler, account_id="ACCT1234",
        base_currency="GBP", initial_funds=1e6,
        fee_model=ZeroFeeModel()
    )

    assert sb2.start_dt == start_dt
    assert sb2.current_dt == start_dt
    assert sb2.exchange == exchange
    assert sb2.account_id == "ACCT1234"
    assert sb2.base_currency == "GBP"
    assert sb2.initial_funds == 1e6
    assert type(sb2.fee_model) == ZeroFeeModel

    tcb2 = dict(
        zip(
            settings.SUPPORTED['CURRENCIES'],
            [0.0] * len(settings.SUPPORTED['CURRENCIES'])
        )
    )
    tcb2["GBP"] = 1e6

    assert sb2.cash_balances == tcb2
    assert sb2.portfolios == {}
    assert sb2.open_orders == {}
Ejemplo n.º 3
0
def test_set_initial_open_orders():
    """
    Check _set_initial_open_orders method for return
    of an empty dictionary.
    """
    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)
    assert sb._set_initial_open_orders() == {}
Ejemplo n.º 4
0
def test_good_set_initial_funds():
    """
    Checks _set_initial_funds sets the initial funds
    correctly if it is a positive floating point value.
    """
    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, initial_funds=1e4)
    assert sb._set_initial_funds(1e4) == 1e4
Ejemplo n.º 5
0
def test_update_sets_correct_time():
    """
    Tests that the update method sets the current
    time correctly.
    """
    start_dt = pd.Timestamp('2017-10-05 08:00:00', tz=pytz.UTC)
    new_dt = pd.Timestamp('2017-10-07 08:00:00', tz=pytz.UTC)
    exchange = ExchangeMock()
    data_handler = DataHandlerMock()

    sb = SimulatedBroker(start_dt, exchange, data_handler)
    sb.update(new_dt)
    assert sb.current_dt == new_dt
Ejemplo n.º 6
0
def test_list_all_portfolio():
    """
    Tests list_all_portfolios method for:
    * If empty portfolio dictionary, return empty list
    * If non-empty, return sorted list via the portfolio IDs
    """
    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)

    # If empty portfolio dictionary, return empty list
    assert sb.list_all_portfolios() == []

    # If non-empty, return sorted list via the portfolio IDs
    sb.create_portfolio(portfolio_id=1234, name="My Portfolio #1")
    sb.create_portfolio(portfolio_id="z154", name="My Portfolio #2")
    sb.create_portfolio(portfolio_id="abcd", name="My Portfolio #3")

    res_ports = sorted([
        p.portfolio_id
        for p in sb.list_all_portfolios()
    ])
    test_ports = ["1234", "abcd", "z154"]
    assert res_ports == test_ports
Ejemplo n.º 7
0
def test_bad_set_initial_funds():
    """
    Checks _set_initial_funds raises ValueError
    if initial funds amount is negative.
    """
    start_dt = pd.Timestamp('2017-10-05 08:00:00', tz=pytz.UTC)
    exchange = ExchangeMock()
    data_handler = DataHandlerMock()

    with pytest.raises(ValueError):
        SimulatedBroker(start_dt, exchange, data_handler, initial_funds=-56.34)
Ejemplo n.º 8
0
def test_good_set_base_currency():
    """
    Checks _set_base_currency sets the currency
    correctly if it is supported by QSTrader.
    """
    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, base_currency="EUR")
    assert sb.base_currency == "EUR"
Ejemplo n.º 9
0
    def _create_broker(self):

        broker = SimulatedBroker(self.start_day,
                                 self.data_handler,
                                 keep_order_time=self.keep_order_time,
                                 deal_volume_time=self.deal_volume_time,
                                 initial_cash=self.initial_cash,
                                 initial_position=self.initial_position,
                                 cac_stat=self.cac_stat)

        return broker
Ejemplo n.º 10
0
def test_bad_set_base_currency():
    """
    Checks _set_base_currency raises ValueError
    if a non-supported currency is attempted to be
    set as the base currency.
    """
    start_dt = pd.Timestamp('2017-10-05 08:00:00', tz=pytz.UTC)
    exchange = ExchangeMock()
    data_handler = DataHandlerMock()

    with pytest.raises(ValueError):
        SimulatedBroker(start_dt, exchange, data_handler, base_currency="XYZ")
Ejemplo n.º 11
0
def test_set_cash_balances():
    """
    Checks _set_cash_balances for zero and non-zero
    initial_funds.
    """
    start_dt = pd.Timestamp('2017-10-05 08:00:00', tz=pytz.UTC)
    exchange = ExchangeMock()
    data_handler = DataHandlerMock()

    # Zero initial funds
    sb1 = SimulatedBroker(
        start_dt, exchange, data_handler, initial_funds=0.0
    )
    tcb1 = dict(
        zip(
            settings.SUPPORTED['CURRENCIES'],
            [0.0] * len(settings.SUPPORTED['CURRENCIES'])
        )
    )
    assert sb1._set_cash_balances() == tcb1

    # Non-zero initial funds
    sb2 = SimulatedBroker(
        start_dt, exchange, data_handler, initial_funds=12345.0
    )
    tcb2 = dict(
        zip(
            settings.SUPPORTED['CURRENCIES'],
            [0.0] * len(settings.SUPPORTED['CURRENCIES'])
        )
    )
    tcb2["USD"] = 12345.0
    assert sb2._set_cash_balances() == tcb2
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
def test_create_portfolio():
    """
    Tests create_portfolio method for:
    * If portfolio_id already in the dictionary keys,
    raise ValueError
    * If it isn't, check that they portfolio and open
    orders dictionary was created correctly.
    """
    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)

    # If portfolio_id isn't in the dictionary, then check it
    # was created correctly, along with the orders dictionary
    sb.create_portfolio(portfolio_id=1234, name="My Portfolio")
    assert "1234" in sb.portfolios
    assert isinstance(sb.portfolios["1234"], Portfolio)
    assert "1234" in sb.open_orders
    assert isinstance(sb.open_orders["1234"], queue.Queue)

    # If portfolio is already in the dictionary
    # then raise ValueError
    with pytest.raises(ValueError):
        sb.create_portfolio(
            portfolio_id=1234, name="My Portfolio"
        )
Ejemplo n.º 14
0
def test_get_account_cash_balance():
    """
    Tests get_account_cash_balance method for:
    * If currency is None, return the cash_balances
    * If the currency code isn't in the cash_balances
    dictionary, then raise ValueError
    * Otherwise, return the appropriate cash balance
    """
    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, initial_funds=1000.0
    )

    # If currency is None, return the cash balances
    sbcb1 = sb.get_account_cash_balance()
    tcb1 = dict(
        zip(
            settings.SUPPORTED['CURRENCIES'],
            [0.0] * len(settings.SUPPORTED['CURRENCIES'])
        )
    )
    tcb1["USD"] = 1000.0
    assert sbcb1 == tcb1

    # If the currency code isn't in the cash_balances
    # dictionary, then raise ValueError
    with pytest.raises(ValueError):
        sb.get_account_cash_balance(currency="XYZ")

    # Otherwise, return appropriate cash balance
    assert sb.get_account_cash_balance(currency="USD") == 1000.0
    assert sb.get_account_cash_balance(currency="EUR") == 0.0
Ejemplo n.º 15
0
def test_withdraw_funds_from_account():
    """
    Tests withdraw_funds_from_account method for:
    * Raising ValueError with negative amount
    * Raising ValueError for lack of cash
    * Correctly setting cash_balances for 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, initial_funds=1e6)

    # Raising ValueError with negative amount
    with pytest.raises(ValueError):
        sb.withdraw_funds_from_account(-4306.23)

    # Raising ValueError for lack of cash
    with pytest.raises(ValueError):
        sb.withdraw_funds_from_account(2e6)

    # Correctly setting cash_balances for a positive amount
    sb.withdraw_funds_from_account(3e5)
    assert sb.cash_balances[sb.base_currency] == 7e5
Ejemplo n.º 16
0
def test_subscribe_funds_to_account():
    """
    Tests subscribe_funds_to_account method for:
    * Raising ValueError with negative amount
    * 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.subscribe_funds_to_account(-4306.23)

    # Correctly setting cash_balances for a positive amount
    sb.subscribe_funds_to_account(165303.23)
    assert sb.cash_balances[sb.base_currency] == 165303.23
Ejemplo n.º 17
0
    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
Ejemplo n.º 18
0
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
Ejemplo n.º 19
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
Ejemplo n.º 20
0
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
Ejemplo n.º 21
0
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