Skip to content

Commit

Permalink
Merge pull request #1996 from QuantConnect/feature-buying-power-model…
Browse files Browse the repository at this point in the history
…-example

Add Example to Writing Algorithms / Reality Modeling / Buying Power
  • Loading branch information
AlexCatarino authored Dec 14, 2024
2 parents d7db968 + d1ba45b commit 247277d
Showing 1 changed file with 134 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,136 @@
<div class="example-fieldset">
<p>The following examples demonstrate some common practices for implementing a custom buying power model.</p>

<h4>Example 1: Always Sufficient Buying Power</h4>
<p>The following algorithm trades protective call strategy. Sometimes, the brokerage's margin requirement differs from the algorithm's default. To avoid errors on order submission at the algorithm level, we can use the <code class="csharp">SecurityPositionGroupModel.Null</code><code class="python">SecurityPositionGroupModel.NULL</code> and <code>NullBuyingPowerModel</code> to disable buying power limitation so the order is sent directly to the broker.</p>
<div class="section-example-container">
<pre class="csharp">using QuantConnect.Securities.Positions;

public class BuyingPowerModelAlgorithm : QCAlgorithm
{
private Symbol _spy;

public override void Initialize()
{
SetStartDate(2023, 10, 1);
SetEndDate(2024, 10, 1);
SetSecurityInitializer(new CustomSecurityInitializer(BrokerageModel, new FuncSecuritySeeder(GetLastKnownPrices)));

// Disable the validations of the default position group buying power model
// that evaluates the buying power of multi-leg strategies
Portfolio.SetPositions(SecurityPositionGroupModel.Null);

// Request SPY data for trading. Set the data normalization mode to raw to allow for a fair comparison in strike price.
_spy = AddEquity("SPY", dataNormalizationMode: DataNormalizationMode.Raw).Symbol;

// Set a scheduled event to rebalance the protective put strategy.
Schedule.On(
DateRules.WeekStart(_spy),
TimeRules.AfterMarketOpen(_spy, 0),
Rebalance
);
}

private void Rebalance()
{
// Select the weekend expiring ATM put for the protective put strategy.
var atmPutContract = OptionChain(_spy)
.Where(x =&gt; x.Right == OptionRight.Put &amp;&amp; x.Expiry &lt; Time.AddDays(6))
.OrderByDescending(x =&gt; x.Expiry)
.ThenBy(x =&gt; Math.Abs(x.Strike - x.UnderlyingLastPrice))
.First();
// Request the ATM put data for trading.
var atmPut = AddOptionContract(atmPutContract).Symbol;

if (Portfolio[_spy].Invested)
{
// If SPY is not assigned, we only need to buy the put.
MarketOrder(atmPut, 1, tag: "Protective Put");
return;
}

// Order the protective put strategy by combo order.
ComboMarketOrder(
new List&lt;Leg&gt; () {
Leg.Create(_spy, 100),
Leg.Create(atmPut, 1)
},
1,
tag: "Protective Put"
);
}
}
public class CustomSecurityInitializer : BrokerageModelSecurityInitializer
{
public CustomSecurityInitializer(IBrokerageModel brokerageModel, ISecuritySeeder securitySeeder)
: base(brokerageModel, securitySeeder)
{
}

public override void Initialize(Security security)
{
base.Initialize(security);
// Do not allow buying power for options; only a hedging strategy with 0 margin is allowed.
security.SetBuyingPowerModel(new NullBuyingPowerModel());
}
}</pre>
<pre class="python">class BuyingPowerModelAlgorithm(QCAlgorithm):
def Initialize(self) -&gt; None:
self.set_start_date(2023, 10, 1)
self.set_end_date(2024, 10, 1)
self.set_security_initializer(CustomSecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices)))

# Disable the validations of the default position group buying power model
# that evaluates the buying power of multi-leg strategies
self.portfolio.set_positions(SecurityPositionGroupModel.NULL)

# Request SPY data for trading. Set the data normalization mode to raw to allow for a fair comparison in strike price.
self.spy = self.add_equity("SPY", data_normalization_mode=DataNormalizationMode.RAW).symbol

# Set a scheduled event to rebalance the protective put strategy.
self.schedule.on(
self.date_rules.week_start(self.spy),
self.time_rules.after_market_open(self.spy, 0),
self.rebalance
)

def rebalance(self) -&gt; None:
# Select the weekend expiring ATM put for the protective put strategy.
chain = self.option_chain(self.spy)
filtered = [x for x in chain if x.right == OptionRight.PUT and x.expiry &lt;= self.time + timedelta(6)]
if not filtered:
return
atm_put_contract = sorted(filtered,
key=lambda x: (-abs(x.strike - x.underlying_last_price), x.expiry),
reverse=True)[0]
# Request the ATM put data for trading.
atm_put = self.add_option_contract(atm_put_contract).symbol

if self.portfolio[self.spy].invested:
# If SPY is not assigned, we only need to buy the put.
self.market_order(atm_put, 1, tag="Protective Put")
else:
# Order the protective put strategy by combo order.
self.combo_market_order([
Leg.create(self.spy, 100),
Leg.create(atm_put, 1)
],
1,
tag="Protective Put"
)

class CustomSecurityInitializer(BrokerageModelSecurityInitializer):
def __init__(self, brokerage_model: IBrokerageModel, security_seeder: ISecuritySeeder):
super().__init__(brokerage_model, security_seeder)
def initialize(self, security: Security):
super().initialize(security)
# Do not allow buying power for options; only a hedging strategy with 0 margin is allowed.
security.SetBuyingPowerModel(NullBuyingPowerModel())</pre>
</div>

<h4>Other Examples</h4>
<p>For more examples, see the following algorithms:</p>

<div class="example-fieldset">
<div class="example-legend">Demonstration Algorithms</div>

<a class="python example-algorithm-link" href="https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/CustomBuyingPowerModelAlgorithm.py" target="_BLANK">
Expand All @@ -20,4 +152,4 @@
<a class="csharp example-algorithm-link" href="https://github.com/QuantConnect/Lean/blob/master/Algorithm.CSharp/NullBuyingPowerOptionBullCallSpreadAlgorithm.cs" target="_BLANK">
NullBuyingPowerOptionBullCallSpreadAlgorithm.cs <span class="badge badge-sm badge-csharp pull-right">C#</span>
</a>
</div>
</div>

0 comments on commit 247277d

Please sign in to comment.