Skip to content
All library documents

Custom Buying Power Rules in Backtests

Article Strategy library · Author: QuantConnect

Summary

This QuantConnect example demonstrates how a custom buying power model can change order sizing and buying-power checks in a backtest. It applies the model to hourly SPY data, rounds the maximum order quantity down to a multiple of 100 shares, and then submits a market order sized at ten times the calculated quantity.

The custom model always reports sufficient buying power and sets both maintenance margin and reserved position buying power to zero. These overrides illustrate how a backtesting engine can be customized, but they also bypass important constraints that normally limit trading and trigger margin calls. The example is therefore useful for understanding the model interface, not as a realistic account or risk setup. It supplies no trading signal, performance results, or evidence that the resulting order behavior would be suitable for live trading.

Key ideas

  • A custom buying power model can alter order sizing and buying-power validation in a backtest.
  • The example rounds calculated maximum order quantities down to multiples of 100 shares.
  • Its model always approves buying power and sets maintenance and reserved position margin to zero.
  • Those overrides bypass constraints that would ordinarily limit orders or prompt margin calls.
  • The example demonstrates platform mechanics rather than a trading strategy or validated live-trading setup.

Tags

Full text
# CustomBuyingPowerModelAlgorithm


# CustomBuyingPowerModelAlgorithm









Demonstration of using custom buying power model in backtesting.
    QuantConnect allows you to model all orders as deeply and accurately as you need.

Demonstration of using custom buying power model in backtesting. QuantConnect allows you to model all orders as deeply and accurately as you need.

## Source (Apache-2.0)

```python
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from AlgorithmImports import *

### <summary>
### Demonstration of using custom buying power model in backtesting.
### QuantConnect allows you to model all orders as deeply and accurately as you need.
### </summary>
### <meta name="tag" content="trading and orders" />
### <meta name="tag" content="transaction fees and slippage" />
### <meta name="tag" content="custom buying power models" />
class CustomBuyingPowerModelAlgorithm(QCAlgorithm):
    '''Demonstration of using custom buying power model in backtesting.
    QuantConnect allows you to model all orders as deeply and accurately as you need.'''

    def initialize(self):
        self.set_start_date(2013,10,1)   # Set Start Date
        self.set_end_date(2013,10,31)    # Set End Date
        security = self.add_equity("SPY", Resolution.HOUR)
        self.spy = security.symbol

        # set the buying power model
        security.set_buying_power_model(CustomBuyingPowerModel())

    def on_data(self, slice):
        if self.portfolio.invested:
            return

        quantity = self.calculate_order_quantity(self.spy, 1)
        if quantity % 100 != 0:
            raise AssertionError(f'CustomBuyingPowerModel only allow quantity that is multiple of 100 and {quantity} was found')

        # We normally get insufficient buying power model, but the
        # CustomBuyingPowerModel always says that there is sufficient buying power for the orders
        self.market_order(self.spy, quantity * 10)


class CustomBuyingPowerModel(BuyingPowerModel):
    def get_maximum_order_quantity_for_target_buying_power(self, parameters):
        quantity = super().get_maximum_order_quantity_for_target_buying_power(parameters).quantity
        quantity = np.floor(quantity / 100) * 100
        return GetMaximumOrderQuantityResult(quantity)

    def has_sufficient_buying_power_for_order(self, parameters):
        return HasSufficientBuyingPowerForOrderResult(True)

    # Let's always return 0 as the maintenance margin so we avoid margin call orders
    def get_maintenance_margin(self, parameters):
        return MaintenanceMargin(0)

    # Override this as well because the base implementation calls GetMaintenanceMargin (overridden)
    # because in C# it wouldn't resolve the overridden Python method
    def get_reserved_buying_power_for_position(self, parameters):
        return parameters.result_in_account_currency(0)

```

Shown in full with attribution under the source's licence. Licence: Apache-2.0

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.