Settlement
Key Concepts
Introduction
After you trade an asset, the brokerage needs to settle the funds in your account. The most common type of settlement is immediate, where the funds are immediately available for trading after the transaction. In some cases, you may have delayed settlement, where you sell an asset and need to wait a few days to spend the cash you receive from the sale. A settlement model simulates these settlement rules.
Set Models
The brokerage model of your algorithm automatically sets the settlement model for each security, but you can override it. To manually set the settlement model of a security, call the SetSettlementModelset_settlement_model method on the Security object.
public override void Initialize()
{
var security = AddEquity("SPY");
// Set a delayed settlement model that settles 7 days after the trade at 8 AM
// This can better mimic actual settlement of some brokerage, providing more realistic fund and margin available
security.SetSettlementModel(new DelayedSettlementModel(7, TimeSpan.FromHours(8)));
} def initialize(self) -> None:
security = self.add_equity("SPY")
# Set a delayed settlement model that settles 7 days after the trade at 8 AM
# This can better mimic actual settlement of some brokerage, providing more realistic fund and margin available
security.set_settlement_model(DelayedSettlementModel(7, timedelta(hours=8)))
You can also set the settlement model in a security initializer. If your algorithm has a universe, use the security initializer technique. In order to initialize single security subscriptions with the security initializer, call AddSecurityInitializeradd_security_initializer before you create the subscriptions.
public class AddSecurityInitializerExampleAlgorithm : QCAlgorithm
{
public override void Initialize()
{
// In the Initialize method, set the security initializer to set models of assets.
AddSecurityInitializer(CustomSecurityInitializer);
}
private void CustomSecurityInitializer(Security security)
{
// Overwrite some of the reality models
security.SetSettlementModel(new DelayedSettlementModel(7, TimeSpan.FromHours(8)));
}
} class AddSecurityInitializerExampleAlgorithm(QCAlgorithm):
def initialize(self) -> None:
# In the Initialize method, set the security initializer to set models of assets.
self.add_security_initializer(self._custom_security_initializer)
def _custom_security_initializer(self, security: Security) -> None:
# Overwrite some of the reality models
security.set_settlement_model(DelayedSettlementModel(7, timedelta(hours=8)))
To view all the pre-built settlement models, see Supported Models.
Default Behavior
The brokerage model of your algorithm automatically sets the settlement model for each security. The default brokerage model is the DefaultBrokerageModel, which sets the settlement model based on the security type and your account type. The following table shows how it sets the settlement models:
| Security Type | Account Type | Settlement Model |
|---|---|---|
| Equity | Cash | DelayedSettlementModel with the default settlement rules |
| Option | Cash | DelayedSettlementModel with the default settlement rules |
| Future | Any | FutureSettlementModel |
For all other cases, the DefaultBrokerageModel uses the ImmediateSettlementModel.
The default delayed settlement rule for US Equity trades is T+2 at 8 AM Eastern Time (ET). For example, if you sell on Monday, the trade settles on Wednesday at 8 AM. The default delayed settlement rule for Future and Option contracts is T+1 at 8 AM.
Model Structure
Settlement models must extend the ISettlementModel interface. Extensions of the ISettlementModel interface must implement the Scanscan and ApplyFundsapply_funds methods. The Scanscan method is automatically called at the top of each hour and it receives a ScanSettlementModelParameters object. The ApplyFundsapply_funds method receives an ApplyFundsSettlementModelParameters object and applies the settlement rules. The ApplyFundsapply_funds method is also automatically called, but its frequency depends on the security type. The ApplyFundsapply_funds method is automatically called when you fill an order for the following security types:
- Equity
- Equity Options
- Crypto
- Forex
- Future Options
- Index Options
The ApplyFundsapply_funds method is automatically called when you close a position for the following security types:
- Futures
- Crypto Futures
- CFD
public class CustomSettlementModelExampleAlgorithm : QCAlgorithm
{
public override void Initialize()
{
var security = AddEquity("SPY");
// Set the custom settlement model of the selected security to reflect actual scenario for more realistic margin available
security.SetSettlementModel(new MySettlementModel());
}
}
// Define the custom settlement model outside of the algorithm
public class MySettlementModel : ISettlementModel
{
public void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsParameters)
{
var currency = applyFundsParameters.CashAmount.Currency;
var amount = applyFundsParameters.CashAmount.Amount;
applyFundsParameters.Portfolio.CashBook[currency].AddAmount(amount);
}
public void Scan(ScanSettlementModelParameters settlementParameters)
{
}
public CashAmount GetUnsettledCash()
{
return new CashAmount(0, "USD");
}
} class CustomSettlementModelExampleAlgorithm(QCAlgorithm):
def initialize(self) -> None:
security = self.add_equity("SPY")
# Set the custom settlement model of the selected security to reflect actual scenario for more realistic margin available
security.set_settlement_model(MySettlementModel())
# Define the custom settlement model outside of the algorithm
class MySettlementModel:
def apply_funds(self, applyFundsParameters: ApplyFundsSettlementModelParameters) -> None:
currency = applyFundsParameters.cash_amount.currency
amount = applyFundsParameters.cash_amount.amount
applyFundsParameters.portfolio.cash_book[currency].add_amount(amount)
def scan(self, settlementParameters: ScanSettlementModelParameters) -> None:
pass
def get_unsettled_cash(self) -> CashAmount:
return CashAmount(0, 'USD')
ApplyFundsSettlementModelParameters objects have the following properties:
ScanSettlementModelParameters objects have the following properties:
You likely don't need to create a custom settlement model because the supported models already implement immediate and delayed settlement rules.
Examples
The following examples demonstrate some common practices for implementing the settlement model.
Example 1: 2-day Settlement
The following algorithm simulates
Interactive Brokers
cash account. According to IB's website, cash positions will be settled in 48 hours. Thus, we can implement
DelayedSettlementModel
to mimic that. We hold the intra-day position of SPY to implement the settlement logic.
public class SettlementModelAlgorithm : QCAlgorithm
{
private Symbol _spy;
public override void Initialize()
{
SetStartDate(2024, 9, 1);
SetEndDate(2024, 12, 31);
// Simulate a cash account of IB.
SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash);
// We need to set the settlement model in the security initializer.
SetSecurityInitializer(new CustomSecurityInitializer(BrokerageModel, SecuritySeeder.Null));
// Request SPY data for trading.
_spy = AddEquity("SPY").Symbol;
}
public override void OnData(Slice slice)
{
// Trade based on updated data.
if (slice.QuoteBars.TryGetValue(_spy, out var bar) && !Portfolio.Invested)
{
// Order based on the current available cash.
var quantity = Math.Floor((Portfolio.Cash - Portfolio.UnsettledCash) / bar.Ask.Close);
if (quantity > 0)
{
MarketOrder(_spy, quantity);
}
}
// Exit position before market close; we only hold the intraday position.
if (slice.Time.Hour == 15 && slice.Time.Minute == 45)
{
Liquidate();
}
}
}
class CustomSecurityInitializer : BrokerageModelSecurityInitializer
{
public CustomSecurityInitializer(IBrokerageModel brokerageModel, ISecuritySeeder securitySeeder)
: base(brokerageModel, securitySeeder)
{
}
public override void Initialize(Security security)
{
base.Initialize(security);
// IB settles cash in 48 hours.
security.SetSettlementModel(new DelayedSettlementModel(2, new TimeSpan(0, 0, 0)));
}
} # region imports
from AlgorithmImports import *
# endregion
class SettlementModelAlgorithm(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2024, 9, 1)
self.set_end_date(2024, 12, 31)
# Simulate a cash account of IB.
self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.CASH)
# We need to set the settlement model in the security initializer.
self.set_security_initializer(CustomSecurityInitializer(self.brokerage_model, SecuritySeeder.NULL))
# Request SPY data for trading.
self.spy = self.add_equity("SPY").symbol
def on_data(self, slice: Slice) -> None:
# Trade based on updated data.
bar = slice.quote_bars.get(self.spy)
if bar and not self.portfolio.invested:
# Order based on the current available cash.
quantity = (self.portfolio.cash - self.portfolio.unsettled_cash) // bar.ask.close
if quantity > 0:
self.market_order(self.spy, quantity)
# Exit position before market close; we only hold the intraday position.
if slice.time.hour == 15 and slice.time.minute == 45:
self.liquidate()
class CustomSecurityInitializer(BrokerageModelSecurityInitializer):
def __init__(self, brokerage_model: IBrokerageModel, security_seeder: ISecuritySeeder):
super().__init__(brokerage_model, security_seeder)
def initialize(self, security: Security) -> None:
super().initialize(security)
# IB settles cash in 48 hours.
security.set_settlement_model(DelayedSettlementModel(2, timedelta(hours=0)))
Example 2: No Unsettled Cash
The following algorithm implements a custom settlement model that states there is always $0 of unsettled cash.
public class CustomSettlementModelAlgorithm : QCAlgorithm
{
private bool _traded;
public override void Initialize()
{
SetStartDate(2024, 9, 1);
SetEndDate(2024, 12, 31);
SetCash(100000);
var security = AddEquity("SPY");
security.SetSettlementModel(new MySettlementModel());
Schedule.On(
DateRules.EveryDay("SPY"),
TimeRules.Every(TimeSpan.FromMinutes(30)),
plotCash
);
_traded = false;
}
private void plotCash()
{
Plot("Settled Cash", "USD", Portfolio.CashBook["USD"].Amount);
Plot("Unsettled Cash", "USD", Portfolio.UnsettledCashBook["USD"].Amount);
}
public override void OnData(Slice data)
{
if (_traded)
return;
MarketOrder("SPY", 1);
MarketOrder("SPY", -1);
_traded = true;
}
}
public class MySettlementModel : ISettlementModel
{
public void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsParameters)
{
var currency = applyFundsParameters.CashAmount.Currency;
var amount = applyFundsParameters.CashAmount.Amount;
applyFundsParameters.Portfolio.CashBook[currency].AddAmount(amount);
}
public void Scan(ScanSettlementModelParameters settlementParameters)
{
}
public CashAmount GetUnsettledCash()
{
return new CashAmount(0, "USD");
}
} class CustomSettlementModelAlgorithm(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2024, 9, 1)
self.set_end_date(2024, 12, 31)
self.set_cash(100000)
security = self.add_equity('SPY')
security.set_settlement_model(MySettlementModel())
self.schedule.on(
self.date_rules.every_day('SPY'),
self.time_rules.every(timedelta(minutes=30)),
self._plot_cash
)
self._traded = False
def _plot_cash(self):
self.Plot("Settled Cash", "USD", self.Portfolio.CashBook["USD"].Amount)
self.Plot("Unsettled Cash", "USD", self.Portfolio.UnsettledCashBook["USD"].Amount)
def on_data(self, data: Slice) -> None:
if self._traded:
return
self.market_order('SPY', 1)
self.market_order('SPY', -1)
self._traded = True
class MySettlementModel:
def apply_funds(self, apply_funds_parameters: ApplyFundsSettlementModelParameters) -> None:
currency = apply_funds_parameters.cash_amount.currency
amount = apply_funds_parameters.cash_amount.amount
apply_funds_parameters.portfolio.cash_book[currency].add_amount(amount)
def scan(self, settlement_parameters: ScanSettlementModelParameters) -> None:
pass
def get_unsettled_cash(self) -> CashAmount:
return CashAmount(0, 'USD')