Hi staff, 

 I have been hitting my head against the wall for weeks now trying to figure this out and learn your platform! I am trying to write a simple bot that buys 0.7 delta call credit spreads. I modified the code to just buy one spread at a time, and it keeps giving me insufficient buying power errors. How can I fix this?

using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Data.Custom.CBOE;
using QuantConnect.Interfaces;
using QuantConnect.Orders;
using QuantConnect.Securities.Option;


namespace QuantConnect.Algorithm.CSharp
{
public class VentralCalibratedProcessor : QCAlgorithm
{
private Symbol _equitySymbol;
private Symbol _optionSymbol;
private QuantConnect.Indicators.RelativeStrengthIndex _rsi;

public decimal MinDeltaLimit = 0.70M;
public decimal MaxTradeSize = 0.25M;

private OptionContract _longCall;
public int DaysBeforeExp;

public override void Initialize()
{
SetStartDate(2018, 1, 1); //Set Start Date
SetEndDate(2018, 3, 1); //Set End Date
SetCash(5000); //Set Strategy Cash

var equity = AddEquity("SPY", Resolution.Minute);
var option = AddOption("SPY", Resolution.Minute);

this.Symbol(option.Symbol);
_equitySymbol = equity.Symbol;
_optionSymbol = option.Symbol;

// 14 day RSI
_rsi = this.RSI(equity.Symbol, 14);

// Filter by 12 strikes and expiration 5 to 10 days
option.SetFilter(universe => universe.IncludeWeeklys().Strikes(-15, 15).Expiration(5, 10));
option.PriceModel = OptionPriceModels.CrankNicolsonFD();
UniverseSettings.Leverage = 4;

// Adding this to reproduce GH issue #2314
SetWarmup(TimeSpan.FromMinutes(1));

// use the underlying equity as the benchmark
SetBenchmark(_equitySymbol);

this.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin);

//Schedule.On(DateRules.EveryDay("SPY"), TimeRules.Every(TimeSpan.FromMinutes(5)), () =>{
//Debug("Specific Time: Fired at : " + Time);
//});

}

/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// Slice object keyed by symbol containing the stock data
public override void OnData(Slice slice)
{
if(this.IsWarmingUp)
return;

if (IsMarketOpen(_equitySymbol) == false)
{
return;
}

if (!Portfolio.Invested)
{

OptionChain chain;
if (slice.OptionChains.TryGetValue(_optionSymbol, out chain))
{

// Find options between delta ranges closest to expiry date
var itmCallDebitSpread = from option in chain
where Math.Abs(option.Greeks.Delta) <= MinDeltaLimit &&
option.Right == OptionRight.Call
orderby option.Expiry ascending, option.Strike
select option;

//foreach(var option in itmCallDebitSpread.ToList()){
//Debug(string.Format("Strike: {0} Expiration: {1} DTE: {2}", option.Strike, option.Expiry, (option.Expiry - Time).Days));
//}

// Get the spread call options
var longCall = itmCallDebitSpread.ToList()[0];
var shortCall = itmCallDebitSpread.ToList()[1];

_longCall = longCall;

// Get debit for potential trade
var spreadDebit = (longCall.AskPrice - shortCall.AskPrice) * 100;

int numOfSpreadsToBuy = 0;
bool canAffordToBuy = true;

// Only allow trade size of percentage of portfolio
var availableCash = Math.Floor(Portfolio.Cash * MaxTradeSize);

while(canAffordToBuy){

numOfSpreadsToBuy++;

// If we can afford to sell, increment amount
if((availableCash - (numOfSpreadsToBuy * spreadDebit)) < 0){
numOfSpreadsToBuy--;
canAffordToBuy = false;
}
}


// Sell the spreads
if(_rsi < 100)
{
//Debug("Spread Debit: $" + Math.Abs(numOfSpreadsToBuy * spreadDebit));
//Debug("Short Call Delta: " + shortCall.Greeks.Delta.ToString());
//Debug("Long Call Delta: " + longCall.Greeks.Delta.ToString());
//Debug(string.Format("Strikes - Long: {0} / Short: {1}", longCall.Strike, shortCall.Strike));
//Debug(string.Format("Expiry Date ({0}): {1}", (longCall.Expiry - Time).Days, longCall.Expiry));

// Buy the spreads (We use a loop for margin reasons)
for(int i = 1; i<= numOfSpreadsToBuy; i++){



}

Buy(longCall.Symbol, 1);
Sell(shortCall.Symbol, 1);
}

}
}
else{

// Close positions based on stop-loss
//foreach(var security in Securities){
//if(security.Value.Holdings.UnrealizedProfitPercent < -0.30M){

//Debug("Stop Loss - Profit Percent (P/L): " + (security.Value.Holdings.UnrealizedProfitPercent * 100) + "%");
//Liquidate(_optionSymbol);

//}
//}

// Close positions before expiration to prevent assignment
if(_longCall != null){
if((_longCall.Expiry - Time).Days <= DaysBeforeExp){
//Liquidate(_optionSymbol);
//Debug("Closed options contracts early.");
}
}

}
}

/// <summary>
/// Order fill event handler. On an order fill update the resulting information is passed to this method.
/// </summary>
/// <param name="orderEvent">Order event details containing details of the evemts</param>
/// <remarks>This method can be called asynchronously and so should only be used by seasoned C# experts. Ensure you use proper locks on thread-unsafe objects</remarks>
public override void OnOrderEvent(OrderEvent orderEvent)
{
//Log(orderEvent.ToString());

var order = Transactions.GetOrderById(orderEvent.OrderId);
if (order.Type == OrderType.OptionExercise){
Log(string.Format("{0}: {1}: {2}", Time, order.Type, orderEvent));
Liquidate();
}
}

public override void OnAssignmentOrderEvent(OrderEvent orderEvent){

Log(orderEvent.ToString());
Liquidate();
}

}
}

 

Backtest Handled Error: Order Error: id: 3, Insufficient buying power to complete order (Value:-26100), Reason: Id: 3, Initial Margin: -13707, Free Margin: 0
Order Error: id: 6, Insufficient buying power to complete order (Value:26050), Reason: Id: 6, Initial Margin: 13707, Free Margin: 0