228 lines
9.5 KiB
C#
228 lines
9.5 KiB
C#
/*
|
||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*
|
||
*/
|
||
|
||
using System;
|
||
using System.Linq;
|
||
using QuantConnect.Data;
|
||
using QuantConnect.Data.Market;
|
||
using QuantConnect.Orders;
|
||
using QuantConnect.Securities;
|
||
using QuantConnect.Securities.Option;
|
||
using QuantConnect.Data.UniverseSelection;
|
||
|
||
namespace QuantConnect.Algorithm.CSharp
|
||
{
|
||
/// <summary>
|
||
/// This example demonstrates how to create a multi asset class trading strategy.
|
||
/// This code is designed for test purposes and can be used with paper brokerage.
|
||
/// All asset classes are not necessarily supported by some brokers. See our website for details.
|
||
/// </summary>
|
||
public class BasicTemplateMultiAssetAlgorithm : QCAlgorithm
|
||
{
|
||
// S&P 500 EMini futures
|
||
private const string TickerSP500 = Futures.Indices.SP500EMini;
|
||
public Symbol SymbolSP500 = QuantConnect.Symbol.Create(TickerSP500, SecurityType.Future, Market.USA);
|
||
|
||
// Google options
|
||
private const string UnderlyingTicker = "GOOG";
|
||
public readonly Symbol Underlying = QuantConnect.Symbol.Create(UnderlyingTicker, SecurityType.Equity, Market.USA);
|
||
public readonly Symbol OptionSymbol = QuantConnect.Symbol.Create(UnderlyingTicker, SecurityType.Option, Market.USA);
|
||
|
||
// Microsoft stock
|
||
private const string TickerMSFT = "MSFT";
|
||
private readonly Symbol SymbolMSFT = QuantConnect.Symbol.Create(TickerMSFT, SecurityType.Equity, Market.USA);
|
||
|
||
// EUR/USD FX spot pair
|
||
private const string TickerEURUSD = "EURUSD";
|
||
private readonly Symbol SymbolEURUSD = QuantConnect.Symbol.Create(TickerEURUSD, SecurityType.Forex, Market.FXCM);
|
||
|
||
private int barCount = 0;
|
||
|
||
public override void Initialize()
|
||
{
|
||
SetStartDate(2014, 01, 01);
|
||
SetEndDate(2014, 02, 01);
|
||
SetCash(1000000);
|
||
|
||
// setting futures
|
||
var futureSP500 = AddFuture(TickerSP500, Resolution.Minute);
|
||
// set our expiry filter for this futures chain
|
||
futureSP500.SetFilter(TimeSpan.FromDays(10), TimeSpan.FromDays(182));
|
||
|
||
// setting up options
|
||
var equity = AddEquity(UnderlyingTicker);
|
||
var option = AddOption(UnderlyingTicker);
|
||
equity.SetDataNormalizationMode(DataNormalizationMode.Raw);
|
||
option.PriceModel = OptionPriceModels.BjerksundStensland();
|
||
// option.EnableGreekApproximation = true;
|
||
// set our expiry filter for this option chain
|
||
option.SetFilter(-2, +2, TimeSpan.FromDays(10), TimeSpan.FromDays(17));
|
||
|
||
// setting up stock
|
||
AddEquity(TickerMSFT);
|
||
|
||
// setting up FX
|
||
AddForex(TickerEURUSD);
|
||
|
||
// specifying zero benchmark
|
||
SetBenchmark(date => 0m);
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
barCount++;
|
||
|
||
if (barCount % 3 == 0)
|
||
{
|
||
if (!Portfolio.Invested)
|
||
{
|
||
foreach (var chain in slice.FutureChains)
|
||
{
|
||
// find the front contract expiring no earlier than in 90 days
|
||
var contract = (
|
||
from futuresContract in chain.Value.OrderBy(x => x.Expiry)
|
||
where futuresContract.Expiry > Time.Date.AddDays(90)
|
||
select futuresContract
|
||
).FirstOrDefault();
|
||
|
||
// if found, trade it
|
||
if (contract != null)
|
||
{
|
||
MarketOrder(contract.Symbol, 1);
|
||
}
|
||
}
|
||
|
||
OptionChain optionChain;
|
||
if (slice.OptionChains.TryGetValue(OptionSymbol, out optionChain))
|
||
{
|
||
// find the second call strike under market price
|
||
var contract = optionChain
|
||
.OrderBy(x => Math.Abs(optionChain.Underlying.Price - x.Strike))
|
||
.ThenByDescending(x => x.Expiry)
|
||
.FirstOrDefault();
|
||
|
||
// if found, trade it
|
||
if (contract != null)
|
||
{
|
||
MarketOrder(contract.Symbol, 1);
|
||
}
|
||
}
|
||
|
||
// trade MSFT
|
||
MarketOrder(SymbolMSFT, 100);
|
||
|
||
// trade FX pair
|
||
MarketOrder(SymbolEURUSD, 100000);
|
||
}
|
||
else
|
||
{
|
||
Liquidate();
|
||
}
|
||
}
|
||
|
||
if (barCount % 3 == 1)
|
||
{
|
||
Log(String.Format("P/L:{0:0.00}, Fees:{1:0.00}, Profit:{2:0.00}, Eq:{3:0.00}, Holdings:{4:0.00}, Vol: {5:0.00}, Margin: {6:0.00}",
|
||
Portfolio.TotalUnrealisedProfit,
|
||
Portfolio.TotalFees,
|
||
Portfolio.TotalProfit,
|
||
Portfolio.TotalPortfolioValue,
|
||
Portfolio.TotalHoldingsValue,
|
||
Portfolio.TotalSaleVolume,
|
||
Portfolio.TotalMarginUsed));
|
||
|
||
foreach (var holding in Securities.Values)
|
||
{
|
||
Log(String.Format(" - {0}, Avg Prc:{1:0.00}, Qty:{2:0.00}, Mkt Prc:{3:0.00}, Mkt Val:{4:0.00}, Unreal P/L: {5:0.00}, Fees: {6:0.00}, Vol: {7:0.00}",
|
||
holding.Symbol.Value,
|
||
holding.Holdings.AveragePrice,
|
||
holding.Holdings.Quantity,
|
||
holding.Holdings.Price,
|
||
holding.Holdings.HoldingsValue,
|
||
holding.Holdings.UnrealizedProfit,
|
||
holding.Holdings.TotalFees,
|
||
holding.Holdings.TotalSaleVolume));
|
||
}
|
||
}
|
||
|
||
if (barCount % 3 == 2)
|
||
{
|
||
foreach (var chain in slice.OptionChains)
|
||
{
|
||
var underlying = Securities[chain.Key.Underlying];
|
||
foreach (var contract in chain.Value)
|
||
{
|
||
Log(String.Format(@"{0} {1},Bid={2} Ask={3} Last={4} OI={5} σ={6:0.00} NPV={7:0.00} Δ={8:0.00} Γ={9:0.00} ν={10:0.00} ρ={11:0.00} Θ={12:0.00} IV={13:0.00}",
|
||
Time.ToString(),
|
||
contract.Symbol.Value,
|
||
contract.BidPrice,
|
||
contract.AskPrice,
|
||
contract.LastPrice,
|
||
contract.OpenInterest,
|
||
underlying.VolatilityModel.Volatility,
|
||
contract.TheoreticalPrice,
|
||
contract.Greeks.Delta,
|
||
contract.Greeks.Gamma,
|
||
contract.Greeks.Vega,
|
||
contract.Greeks.Rho,
|
||
contract.Greeks.Theta / 365.0m,
|
||
contract.ImpliedVolatility));
|
||
}
|
||
}
|
||
|
||
foreach (var chain in slice.FutureChains)
|
||
{
|
||
foreach (var contract in chain.Value)
|
||
{
|
||
Log(String.Format("{0}, {1}, Bid={2} Ask={3} Last={4} OI={5}",
|
||
contract.Symbol.Value,
|
||
Time,
|
||
contract.BidPrice,
|
||
contract.AskPrice,
|
||
contract.LastPrice,
|
||
contract.OpenInterest));
|
||
}
|
||
}
|
||
}
|
||
|
||
foreach (var kpv in slice.QuoteBars)
|
||
{
|
||
Console.WriteLine("---> QuoteBar: {0}, {1}, {2}", Time, kpv.Key.Value, kpv.Value.Close.ToString("0.00"));
|
||
}
|
||
|
||
foreach (var kpv in slice.Bars)
|
||
{
|
||
Console.WriteLine("---> Bar: {0}, {1}, {2}", Time, kpv.Key.Value, kpv.Value.Close.ToString("0.00"));
|
||
}
|
||
}
|
||
|
||
/// <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());
|
||
}
|
||
|
||
}
|
||
}
|