Transaction Fees
Key Concepts
Introduction
Your orders incur a transaction fee when a brokerage fills them in the market. LEAN uses transaction fee models in backtesting to model the live trading fees you would incur with the strategy. Transaction fee models make backtest results more realistic. To give your backtests the most accurate fees, LEAN contains transaction fee models that model the fee structure of many popular brokerages.
Set Models
The brokerage model of your algorithm automatically sets the fee model for each security, but you can override it. To manually set the fee model of a security, call the SetFeeModel
set_fee_model
method on the Security
object.
public override Initialize() { var security = AddEquity("SPY"); // Set the fee model for the requested security to backtest with the most realistic scenario // Constant fee model of 0 dollar is accurate for the commission-free brokerage security.SetFeeModel(new ConstantFeeModel(0)); }
def initialize(self): security = self.add_equity("SPY") # Set the fee model for the requested security to backtest with the most realistic scenario # Constant fee model of 0 dollar is accurate for the commission-free brokerage security.set_fee_model(ConstantFeeModel(0))
You can also set the fee model in a security initializer. If your algorithm has a dynamic universe, use the security initializer technique. In order to initialize single security subscriptions with the security initializer, call SetSecurityInitializer
set_security_initializer
before you create the subscriptions.
public class BrokerageModelExampleAlgorithm : QCAlgorithm { public override void Initialize() { // In the Initialize method, set the security initializer to seed initial the prices and models of assets. SetSecurityInitializer(new MySecurityInitializer(BrokerageModel, new FuncSecuritySeeder(GetLastKnownPrices))); } } public class MySecurityInitializer : BrokerageModelSecurityInitializer { public MySecurityInitializer(IBrokerageModel brokerageModel, ISecuritySeeder securitySeeder) : base(brokerageModel, securitySeeder) {} public override void Initialize(Security security) { // First, call the superclass definition. // This method sets the reality models of each security using the default reality models of the brokerage model. base.Initialize(security); // Next, overwrite some of the reality models security.SetFeeModel(new ConstantFeeModel(0)); } }
class BrokerageModelExampleAlgorithm(QCAlgorithm): def initialize(self) -> None: # In the Initialize method, set the security initializer to seed initial the prices and models of assets. self.set_security_initializer(MySecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices))) # Outside of the algorithm class class MySecurityInitializer(BrokerageModelSecurityInitializer): def __init__(self, brokerage_model: IBrokerageModel, security_seeder: ISecuritySeeder) -> None: super().__init__(brokerage_model, security_seeder) def initialize(self, security: Security) -> None: # First, call the superclass definition. # This method sets the reality models of each security using the default reality models of the brokerage model. super().initialize(security) # Next, overwrite some of the reality models security.set_fee_model(ConstantFeeModel(0))
In live trading, the SetFeeModel
set_fee_model
method isn't ignored. If we use order helper methods like SetHoldings
set_holdings
, the fee model helps to calculate the order quantity. However, the algorithm doesn't update the cash book with the fee from the fee model. The algorithm uses the actual fee from the brokerage to update the cash book.
To view all the pre-built fee models, see Supported Models.
Default Behavior
The brokerage model of your algorithm automatically sets the fill model for each security. The default brokerage model is the DefaultBrokerageModel
, which set the ConstantFeeModel with no fees for Forex, CFD, and Crypto assets and sets the InteractiveBrokersFeeModel for the remaining asset classes.
Model Structure
Fee models should extend the FeeModel
class. Extensions of the FeeModel
class must implement the GetOrderFee
get_order_fee
method, which receives OrderFeeParameters
and returns an OrderFee
that represents a cash amount in a currency.
public class CustomFeeModelExampleAlgorithm : QCAlgorithm { public override void Initialize() { // In the Initialize method, set the custom fee model for an added security to use the custom model var security = AddEquity("SPY"); security.SetFeeModel(new MyFeeModel()); } } // Define the custom fee model public class MyFeeModel : FeeModel { public override OrderFee GetOrderFee(OrderFeeParameters parameters) { return new OrderFee(new CashAmount(0.5m, "USD")); } }
class CustomFeeModelExampleAlgorithm(QCAlgorithm): def initialize(self) -> None: # In the Initialize method, set the custom fee model for an added security to use the custom model security = self.add_equity("SPY") security.set_fee_model(MyFeeModel()) # Define the custom fee model class MyFeeModel(FeeModel): def get_order_fee(self, parameters: OrderFeeParameters) -> OrderFee: return OrderFee(CashAmount(0.5, 'USD'))
For a full example algorithm, see this backtestthis backtest.
The OrderFeeParameters
object has the following members:
Zero Transaction Fees
To model zero transaction fees, use the ConstantFeeModel with zero as fee
.
public override Initialize() { var security = AddEquity("SPY"); security.SetFeeModel(new ConstantFeeModel(fee: 0m)); }
def initialize(self): security = self.add_equity("SPY") security.set_fee_model(ConstantFeeModel(fee=0))