Skip to content
All library documents

Modeling Minimum Cash Requirements in a Brokerage Backtest

Article Strategy library · Author: QuantConnect

Summary

This example shows how a backtest can incorporate brokerage-specific order restrictions and fees through a custom brokerage model. It defines a rule that rejects an order when its estimated cost would reduce portfolio cash below a required minimum, and emits a warning explaining the rejection. A simple buy-and-hold example uses this model while repeatedly attempting to set a target holding; after a failed purchase, it reduces the target allocation and retries.

The sample uses an equity at second-level resolution over a short date range and initializes a cash balance and minimum reserve. It demonstrates a practical way to make simulated order acceptance reflect account constraints, rather than assuming every requested order can be placed. The example does not compare results against a real broker or address broader brokerage rules, such as margin treatment, changing fees, or different asset classes, so the custom check should be treated as a narrow illustration.

Key ideas

  • A custom brokerage model can enforce account-specific order acceptance rules during a backtest.
  • The example rejects an order if its estimated cost would leave less than the required cash reserve.
  • Rejected purchases prompt the sample strategy to reduce its target allocation before retrying.
  • Brokerage constraints can improve simulation realism, but this example models only a minimum cash balance rule.

Tags

Full text
# BrokerageModelAlgorithm


# BrokerageModelAlgorithm









Custom brokerage model that requires clients to maintain a minimum cash balance

Demonstrate the usage of the BrokerageModel property to help improve backtesting accuracy through simulation of a specific brokerage's rules around restrictions on submitting orders as well as fee structure.

## 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>
### Demonstrate the usage of the BrokerageModel property to help improve backtesting
### accuracy through simulation of a specific brokerage's rules around restrictions
### on submitting orders as well as fee structure.
### </summary>
### <meta name="tag" content="trading and orders" />
### <meta name="tag" content="brokerage models" />
class BrokerageModelAlgorithm(QCAlgorithm):
    def initialize(self):

        self.set_cash(100000)            # Set Strategy Cash
        self.set_start_date(2013,10,7)    # Set Start Date
        self.set_end_date(2013,10,11)     # Set End Date
        self.add_equity("SPY", Resolution.SECOND)
        
        # there's two ways to set your brokerage model. The easiest would be to call
        # self.set_brokerage_model( BrokerageName ) # BrokerageName is an enum
        # self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE)
        # self.set_brokerage_model(BrokerageName.DEFAULT)

        # the other way is to call SetBrokerageModel( IBrokerageModel ) with your
        # own custom model. I've defined a simple extension to the default brokerage
        # model to take into account a requirement to maintain 500 cash in the account at all times
        self.set_brokerage_model(MinimumAccountBalanceBrokerageModel(self,500.00))
        self.last = 1   
        
    def on_data(self, slice):
        # Simple buy and hold template
        if not self.portfolio.invested:
            self.set_holdings("SPY", self.last)
            if self.portfolio["SPY"].quantity == 0:
                # each time we fail to purchase we'll decrease our set holdings percentage
                self.debug(str(self.time) + " - Failed to purchase stock")
                self.last *= 0.95
            else:
                self.debug("{} - Purchased Stock @ SetHoldings( {} )".format(self.time, self.last))


class MinimumAccountBalanceBrokerageModel(DefaultBrokerageModel):
    '''Custom brokerage model that requires clients to maintain a minimum cash balance'''
    def __init__(self, algorithm, minimum_account_balance):
        self.algorithm = algorithm
        self.minimum_account_balance = minimum_account_balance
    
    def can_submit_order(self,security, order, message):
        '''Prevent orders which would bring the account below a minimum cash balance'''
        message = None
        # we want to model brokerage requirement of minimum_account_balance cash value in account
        order_cost = order.get_value(security)
        cash = self.algorithm.portfolio.cash
        cash_after_order = cash - order_cost
        if cash_after_order < self.minimum_account_balance:
            # return a message describing why we're not allowing this order
            message = BrokerageMessageEvent(BrokerageMessageType.WARNING, "InsufficientRemainingCapital", "Account must maintain a minimum of ${0} USD at all times. Order ID: {1}".format(self.minimum_account_balance, order.id))
            self.algorithm.error(str(message))
            return False
        return True

```

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.