Skip to content

Instantly share code, notes, and snippets.

@yellowandy
Created February 17, 2018 04:38
Show Gist options
  • Save yellowandy/d96c0d78a8e699a2afb5c2367becda80 to your computer and use it in GitHub Desktop.
Save yellowandy/d96c0d78a8e699a2afb5c2367becda80 to your computer and use it in GitHub Desktop.
using System;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Orders;
using QuantConnect.Securities;
using QuantConnect.Securities.Option;
using QuantConnect.Indicators;
namespace QuantConnect
{
/*
* Basic Template Algorithm
*
* The underlying QCAlgorithm class has many methods which enable you to use QuantConnect.
* We have explained some of these here, but the full base class can be found at:
* https://github.com/QuantConnect/Lean/tree/master/Algorithm
*/
public class GreenGooseAlgorithm : QCAlgorithm
{
private const string UnderlyingTicker = "SPY";
public readonly Symbol Underlying = QuantConnect.Symbol.Create(UnderlyingTicker, SecurityType.Equity, Market.USA);
public readonly Symbol OptionSymbol = QuantConnect.Symbol.Create(UnderlyingTicker, SecurityType.Option, Market.USA);
public Option option;
private Slice lastSlice = null;
private RelativeStrengthIndex rsi2;
private string lastOrderSymbol = null;
private decimal lastOrderPrice = 0;
public override void Initialize()
{
// backtest parameters
SetStartDate(2016, 06, 01); //Set Start Date
SetEndDate(2016, 07, 03); //et End Date
// cash allocation
SetCash(25000);
AddEquity(UnderlyingTicker, Resolution.Hour);
option = AddOption(UnderlyingTicker);
option.SetFilter(universe => from symbol in universe
.Expiration(TimeSpan.Zero, TimeSpan.FromDays(14))
select symbol);
rsi2 = RSI(Underlying, 2, Indicators.MovingAverageType.Simple);
//Setup all events
scheduleEvents();
}
public void scheduleEvents()
{
//Open
Schedule.On(DateRules.EveryDay(Underlying), TimeRules.BeforeMarketClose(Underlying, 10), () =>
{
Log("EveryDay.SPY 10 min before close: Fired at: " + Time);
openGreenGooseOrder();
});
//Gap open/close
Schedule.On(DateRules.EveryDay(Underlying), TimeRules.AfterMarketOpen(Underlying), () =>
{
Log("Checking if we should close green goose on market open: " + Time);
closeGreenGooseOrderForGaps();
});
//Regular closes
Schedule.On(DateRules.EveryDay(Underlying), TimeRules.At(10, 0), () =>
{
Log("Checking if we should close green goose: " + Time);
closeGreenGooseOrder();
});
Schedule.On(DateRules.EveryDay(Underlying), TimeRules.At(10, 30), () =>
{
Log("Checking if we should close green goose: " + Time);
closeGreenGooseOrder();
});
Schedule.On(DateRules.EveryDay(Underlying), TimeRules.At(11, 0), () =>
{
Log("Checking if we should close green goose: " + Time);
closeGreenGooseOrder();
});
Schedule.On(DateRules.EveryDay(Underlying), TimeRules.At(11, 30), () =>
{
Log("Checking if we should close green goose: " + Time);
closeGreenGooseOrder();
});
Schedule.On(DateRules.EveryDay(Underlying), TimeRules.At(12, 00), () =>
{
Log("Checking if we should close green goose: " + Time);
closeGreenGooseOrder();
});
Schedule.On(DateRules.EveryDay(Underlying), TimeRules.At(12, 30), () =>
{
Log("Checking if we should close green goose: " + Time);
closeGreenGooseOrder();
});
Schedule.On(DateRules.EveryDay(Underlying), TimeRules.At(13, 00), () =>
{
Log("Checking if we should close green goose: " + Time);
closeGreenGooseOrder();
});
}
//public void getAtmOptionContracts()
//{
// option
// var atmContract = chain
// .OrderByDescending(x => x.Expiry)
// .ThenBy(x => Math.Abs(chain.Underlying.Price - x.Strike))
// .FirstOrDefault();
//}
public void closeGreenGooseOrderForGaps()
{
}
public void closeGreenGooseOrder()
{
Log("Calling close green goose.....");
if (Securities[UnderlyingTicker].Holdings.Quantity > 0)
{
Log("Closing: found open orders to close......");
}
}
public decimal calculatePercentageDifference(decimal startPrice, decimal endPrice)
{
Log("Staring to calculate percentDifference: " + startPrice + " " + endPrice);
return (endPrice - startPrice) / startPrice;
}
public void buyOptionsATM(Slice slice, string optionType)
{
Log("Staring to buy option with slice: " + slice);
OptionChain chain;
if (slice.OptionChains.TryGetValue(OptionSymbol, out chain))
{
var optionRight = OptionRight.Put;
if(optionType == "Call" || optionType == "call") {
Log("Selected call right");
optionRight = OptionRight.Call;
}
else if(optionType == "Put" || optionType == "put") {
Log("Selected put right");
optionRight = OptionRight.Put;
}
var contract = (
from optionContract in chain.OrderByDescending(x => x.Expiry)
.ThenBy(x => Math.Abs(chain.Underlying.Price - x.Strike))
where optionContract.Right == optionRight
select optionContract
).FirstOrDefault();
if (contract != null)
{
Log("Placing market order for " + contract.Symbol);
//MarketOrder(contract.Symbol, 100);
SetHoldings(contract.Symbol, .15);
}
else
{
Log("------> Unable to find contract when trying to open norder");
Log("----------->" + optionRight);
Log("----------->" + slice);
}
}
else
{
Log("------> Unable to find option chain when trying to open order 2");
}
}
public void openGreenGooseOrder()
{
Log("Opening green gose order");
if (!rsi2.IsReady) return;
if (rsi2 <= 15)
{
Log("RSI Less than 15 buying call options");
buyOptionsATM(lastSlice, "Call");
}
else if (rsi2 >= 85)
{
Log("RSI greater than 85 buying options");
buyOptionsATM(lastSlice, "Put");
}
else {
Log("Not opening trade, RSI not a good value: " + rsi2);
}
}
/// <summary>
/// Event - v3.0 DATA EVENT HANDLER: (Pattern) Basic template for user to override for receiving all subscription data in a single event
/// </summary>
/// <param name="slice">The current slice of data keyed by symbol string</param>
public override void OnData(Slice slice)
{
lastSlice = slice;
// Log("Got on data slice at time " + slice.Time);
if (IsWarmingUp) { return; }
// if (!rsi2.IsReady) return;
OptionChain chain;
if(lastOrderSymbol == null) {
//Log("No last open orders, nothing to do");
return;
}
if (slice.OptionChains.TryGetValue(OptionSymbol, out chain))
{
// find the second call strike under market price expiring today
var contract = (
from optionContract in chain.OrderByDescending(x => x.Strike)
where optionContract.Symbol == lastOrderSymbol
select optionContract
).FirstOrDefault();
if(contract != null) {
Log("Last price is: " + contract.LastPrice);
var percentDifference = calculatePercentageDifference(lastOrderPrice, contract.LastPrice);
Log("Percentage difference is: " + percentDifference);
if(percentDifference >= .20M || percentDifference <= -.10m) {
Liquidate(lastOrderSymbol);
lastOrderSymbol = null;
}
}
Log("All done....");
}
//return;
// // slice has lots of useful information
// TradeBars bars = data.Bars;
//Splits splits = data.Splits;
//Dividends dividends = data.Dividends;
////Get just this bar.
//TradeBar bar;
//if (bars.ContainsKey("SPY")) bar = bars["SPY"];
//if (!Portfolio.HoldStock)
//{
// // place an order, positive is long, negative is short.
// // int quantity = Portfolio.Cash / bar.Close;
// // Order("SPY", quantity);
// // or request a fixed fraction of a specific asset.
// // +1 = 100% long. -2 = short all capital with 2x leverage.
// SetHoldings("SPY", 1);
// // debug message to your console. Time is the algorithm time.
// // send longer messages to a file - these are capped to 10kb
// Debug("Purchased SPY on " + Time.ToShortDateString());
// //Log("This is a longer message send to log.");
//}
}
public override void OnOrderEvent(OrderEvent fill)
{
lastOrderSymbol = fill.Symbol;
lastOrderPrice = fill.FillPrice;
string message = String.Format("**************************** Order status:{0} quantity:{1} x symbol:{2} fill price:{3} commission={4} OrderId={5}",
fill.Status.ToString(),
fill.FillQuantity,
fill.Symbol,
fill.FillPrice,
fill.OrderFee,
fill.OrderId);
Log(message);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment