| Overall Statistics |
|
Total Trades 213 Average Win 0.23% Average Loss -0.03% Compounding Annual Return 11.512% Drawdown 3.800% Expectancy 4.730 Net Profit 23.667% Sharpe Ratio 0.865 Loss Rate 27% Win Rate 73% Profit-Loss Ratio 6.86 Alpha 0.069 Beta 0.286 Annual Standard Deviation 0.092 Annual Variance 0.009 Information Ratio 0.356 Tracking Error 0.122 Treynor Ratio 0.279 Total Fees $207.00 |
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Algorithm;
using QuantConnect.Data.Market;
namespace QuantConnect {
/// <summary>
/// QuantConnect QuantFramework Algorithm
///
/// Alpha Generation Module:
///
/// </summary>
public partial class QCUQuantFramework : QCAlgorithm {
/// <summary>
/// Alpha Generator Module:
/// </summary>
public class ModuleAlpha {
/********************************************************
* PRIVATE VARIABLES
*********************************************************/
//Strategy Settings:
private Symbol _cashAsset;
private Symbol _vixSymbol = QuantConnect.Symbol.Create("VIX", SecurityType.Base, Market.USA);
private decimal _vix = 20m;
private decimal _vixLowerBound = 10m;
private decimal _vixUpperBound = 40m;
private int _rebalancePeriod = 4;
private decimal _cashTolerance = 0.01m;
private decimal _minimumDeployedCapital = -0.25m;
//Working Variables:
private DateTime _lastRebalance = new DateTime(2004, 1, 2);
private decimal _activePortfolioFraction = 0.3333m;
private decimal _deployedCapital = 1m;
private QCUQuantFramework _algorithm;
private List<Symbol> _assets = new List<Symbol>();
private decimal _safeCapital = 0m;
private decimal _adjustLeverageToOne = 0.5m;
private Dictionary<Symbol, decimal> _historicalPrices = new Dictionary<Symbol, decimal>();
private Dictionary<Symbol, decimal> _activeFractionsBySymbol = new Dictionary<Symbol, decimal>();
private Dictionary<Symbol, decimal> _relativePrices = new Dictionary<Symbol, decimal>();
/********************************************************
* PUBLIC PROPERTIES
*********************************************************/
/********************************************************
* PUBLIC CONSTRUCTOR
*********************************************************/
/// <summary>
/// Initialize the Alpha Manager:
/// </summary>
/// <param name="algorithm">Algorithm instance</param>
public ModuleAlpha(QCUQuantFramework algorithm) {
this._algorithm = algorithm;
_cashAsset = _algorithm.CashAsset;
_activePortfolioFraction = 1m;
}
public void UpdateAssets(List<Symbol> assets) {
this._assets = assets;
if (assets.Count > 0) {
_activePortfolioFraction = 1m / ((decimal)assets.Count);
//Remove the cash asset from the active portfolio.
_assets.Remove(_cashAsset);
}
//Find default fraction of assets
foreach (var symbol in _assets) {
if (!_activeFractionsBySymbol.ContainsKey(symbol)) {
_activeFractionsBySymbol.Add(symbol, _activePortfolioFraction);
_relativePrices.Add(symbol, 1);
}
}
}
/********************************************************
* PUBLIC METHODS
*********************************************************/
/// <summary>
/// Generate the Alpha Signal. Create a Symbol with a Strength of Conviction Indicator:
/// </summary>
/// <param name="prices">Latest prices data</param>
/// <returns>List of commands to trade</returns>
public Dictionary<Symbol, PortfolioTarget> Scan(TradeBars prices, List<Symbol> universe) {
var targets = new Dictionary<Symbol, PortfolioTarget>();
if (!prices.ContainsKey(_vixSymbol)) return targets;
try {
if (_algorithm.Time > _lastRebalance.Date.AddDays(_rebalancePeriod)) {
_vix = prices[_vixSymbol].Close;
_lastRebalance = _algorithm.Time;
//Scale VIX fractionally 0-1 for 10-30.
_deployedCapital = 1 - ((_vix - _vixLowerBound) / (_vixUpperBound - _vixLowerBound));
//Set minimum deployed (set min to negative to allow shorts)
if (_deployedCapital < _minimumDeployedCapital) _deployedCapital = _minimumDeployedCapital;
//Fraction of capital preserved for bonds:
_safeCapital = 1 - _deployedCapital - _cashTolerance;
targets.Add(_cashAsset, new PortfolioTarget(_cashAsset, _safeCapital * _adjustLeverageToOne));
//Use rotational logic to reduce allocation to poorly performing stocks:
foreach (Symbol symbol in prices.Keys) {
var price = prices[symbol].Close;
//Find the relative prices of each stock sinc rebalance. e.g. 0.97, 1.03, 0.80
if (!_historicalPrices.ContainsKey(symbol)) _historicalPrices.Add(symbol, price);
_relativePrices[symbol] = (price / _historicalPrices[symbol]);
}
// Baseline of all asset performance
var sum = _relativePrices.Values.Sum();
foreach (Symbol symbol in _assets) {
//HACK: this is quite dangerous to leave a asset when you don't have price
// to make this work quickly I am going with this approach.
if (!prices.ContainsKey(symbol)) continue;
if (sum > 0) {
_activeFractionsBySymbol[symbol] = (_relativePrices[symbol] / sum);
} else {
_activeFractionsBySymbol[symbol] = 0;
}
if (symbol != _cashAsset) {
targets.Add(symbol, new PortfolioTarget(symbol, _deployedCapital * _activeFractionsBySymbol[symbol] * _adjustLeverageToOne));
}
//Save to calculate the rotational fraction.
_historicalPrices[symbol] = prices[symbol].Close;
}
}
} catch (Exception err) {
_algorithm.Error("AlphaModule.Scan: Error -" + err.Message + err.ToString());
}
return targets;
}
}
} // End of QCU QuantFramework
} // End of QuantConnect Namespaceusing System;
using System.Collections.Generic;
using QuantConnect.Algorithm;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Data.Market;
namespace QuantConnect {
/// <summary>
/// QuantConnect QuantFramework Algorithm
///
/// Asset/Universe Selection Module:
///
/// </summary>
public partial class QCUQuantFramework : QCAlgorithm {
/// <summary>
/// Asset Screening Module:
/// </summary>
public partial class ModuleAssets {
private decimal emaPeriod = 10m;
/********************************************************
* PRIVATE VARIABLES
*********************************************************/
//Working Variables:
private QCUQuantFramework _algorithm;
private Dictionary<Symbol, Asset> _assets;
private int _daysAnalysed;
private List<Symbol> _universe;
/********************************************************
* PUBLIC PROPERTIES
*********************************************************/
/// <summary>
/// Public access to the asset properties:
/// </summary>
public Dictionary<Symbol, Asset> Assets {
get {
return _assets;
}
}
/********************************************************
* PUBLIC CONSTRUCTOR
*********************************************************/
/// <summary>
/// Initialize the Asset Manager:
/// </summary>
/// <param name="algorithm">Instance of the algorithm required</param>
public ModuleAssets(QCUQuantFramework algorithm) {
_daysAnalysed = 0;
_algorithm = algorithm;
_universe = new List<Symbol>();
_assets = new Dictionary<Symbol, Asset>();
// subscriptions added via universe selection will have this resolution
_algorithm.UniverseSettings.Resolution = Resolution.Daily;
// force securities to remain in the universe for a minimm of 7 hours
_algorithm.UniverseSettings.MinimumTimeInUniverse = TimeSpan.FromHours(7);
// add universe for the 90th dollar volume percentile
//_algorithm.AddUniverse(_algorithm.Universe.DollarVolume.Percentile(90));
_algorithm.AddUniverse(_algorithm.Universe.DollarVolume.Top(10));
// special case cash asset
_algorithm.AddEquity(_algorithm.CashAsset.ToString());
}
public void OnSecuritiesChanged(SecurityChanges changes) {
// liquidate securities that fell out of our universe
foreach (var security in changes.RemovedSecurities) {
if (_assets.ContainsKey(security.Symbol)) {
_assets.Remove(security.Symbol);
}
}
// invest in securities just added to our universe
foreach (var security in changes.AddedSecurities) {
if (!_assets.ContainsKey(security.Symbol)) {
_assets.Add(security.Symbol, new Asset(security.Symbol, Industry.All, 0, 0));
}
}
}
/// <summary>
/// At the start of end of each trading day, select the stock universe for next day:
/// </summary>
/// <returns></returns>
public List<Symbol> UpdateUniverse() {
_universe.Clear();
try {
//Perform any math / filtering / data search required to select the algorithm symbols for this next period.
foreach (var symbol in _assets.Keys) {
_universe.Add(symbol);
}
} catch (Exception err) {
_algorithm.Error("AssetModule.ScreenUniverse(): Error - " + err.Message);
}
return _universe;
}
/// <summary>
/// Update the asset properties where possible
/// </summary>
/// <param name="symbol">Symbol of the asset we're setting.</param>
/// <param name="volume"></param>
public void UpdateAssetProperties(Symbol symbol, TradeBar tradeBar) {
if (_assets.ContainsKey(symbol)) {
Asset asset = _assets[symbol];
if (asset.Price == 0) asset.Price = tradeBar.Close;
if (asset.Volume == 0) asset.Volume = tradeBar.Volume;
decimal multiplier = 1 / emaPeriod;
//E10 Exponential moving average prices:
asset.Price = multiplier * tradeBar.Close + (1 - multiplier) * asset.Price;
asset.Volume = multiplier * tradeBar.Volume + (1 - multiplier) * asset.Volume;
// Update the end of day count of days counted:
_daysAnalysed++;
}
}
}
} // End of QCU QuantFramework
} // End of QuantConnect Namespaceusing System;
using System.Collections.Generic;
using MathNet.Numerics;
using MathNet.Numerics.Statistics;
using QuantConnect.Algorithm;
using QuantConnect.Data.Market;
using System.Linq;
namespace QuantConnect {
/// <summary>
/// QuantConnect QuantFramework Algorithm
///
/// Execution Management Module:
///
/// </summary>
public partial class QCUQuantFramework : QCAlgorithm {
/// <summary>
/// Trading Execution Module: with two execution style out of the box:
/// -> ImmediateExecution - Send to market now.
/// -> StandardDeviation - Send to market later.
/// </summary>
public class ModuleExecute {
/********************************************************
* PRIVATE VARIABLES
*********************************************************/
private QCUQuantFramework _algorithm;
private Dictionary<Symbol, decimal> _target;
private ExecutionTechnique _technique;
private TradeBars _prices;
//Standard deviation strategy variable:
private int _devWindowPeriod = 60;
private double _buyPoint = -2;
private double _sellPoint = 2;
private double _extremePoint = 3.6;
//Standard deviation working varibles
private Dictionary<Symbol, RunningStatistics> _deviationsStatistics;
private Dictionary<Symbol, double> _deviations;
private Dictionary<Symbol, FixedLengthQueue<double>> _priceQueue;
private int _devSampleCount = 0;
/********************************************************
* PUBLIC PROPERTIES
*********************************************************/
/********************************************************
* PUBLIC CONSTRUCTOR
*********************************************************/
/// <summary>
/// Initialize the Execution Manager:
/// </summary>
/// <param name="algorithm">Algorithm instance</param>
public ModuleExecute(QCUQuantFramework algorithm, ExecutionTechnique technique = ExecutionTechnique.Immediate) {
//Common Execution Parameters
this._algorithm = algorithm;
this._target = new Dictionary<Symbol, decimal>();
this._technique = technique;
//StdDev Working Parameters
this._deviations = new Dictionary<Symbol, double>();
this._deviationsStatistics = new Dictionary<Symbol, RunningStatistics>();
this._priceQueue = new Dictionary<Symbol, FixedLengthQueue<double>>();
}
/********************************************************
* PUBLIC METHODS
*********************************************************/
/// <summary>
/// Set the target quantity for a symbol. Let the risk manager processing get us to this target:
/// </summary>
/// <param name="symbol">Desired asset</param>
/// <param name="quantity">Desired quantity</param>
public void SetPortfolioTarget(Dictionary<Symbol, PortfolioTarget> targets) {
try {
foreach (var symbol in targets.Keys) {
if (!_target.ContainsKey(symbol)) {
_target.Add(symbol, targets[symbol].Signal);
} else {
_target[symbol] = targets[symbol].Signal;
}
}
} catch (Exception err) {
_algorithm.Error("ModuleExecute.SetPortfolioTarget(): " + err.Message);
}
}
/// <summary>
/// Manage the execution of the algorithm delta of desired -> actual portfolio holdings:
/// </summary>
public void Execute(TradeBars prices) {
try {
_prices = prices;
switch (_technique) {
//Send the order to market immediate:
case ExecutionTechnique.Immediate:
ExecuteImmediate();
break;
//Execute with at favourable standard deviations:
// - Use online stdDev techinque to track prices, when significantly better than mean purchase.
case ExecutionTechnique.StandardDeviation:
ExecuteStandardDeviation();
break;
}
} catch (Exception err) {
_algorithm.Error("ModuleExecute.Analyse(): " + err.Message);
}
}
/// <summary>
/// Execute the trade immediately
/// </summary>
private void ExecuteImmediate() {
int orderId = 0;
decimal deltaQuantity = 0;
var delta = new Dictionary<string, decimal>();
var remove = new List<string>();
//Find the difference in number target to holdings:
foreach (Symbol security in _target.Keys) {
string symbol = security.ToString();
decimal total = _algorithm.Portfolio.TotalHoldingsValue + _algorithm.Portfolio.Cash * _algorithm.Securities[symbol].Leverage;
//2. Difference between our target % and our current holdings: (relative +- number).
decimal deltaValue = (total * _target[symbol]) - _algorithm.Portfolio[symbol].HoldingsValue;
//Potential divide by zero error for zero prices assets.
if (Math.Abs(_algorithm.Securities[symbol].Price) > 0) {
//3. Now rebalance the symbol requested:
deltaQuantity = Math.Floor(deltaValue / _algorithm.Securities[symbol].Price);
}
//Determine if we need to place an order:
if (Math.Abs(deltaQuantity) > 0) {
delta.Add(symbol, deltaQuantity);
} else {
//Remove the targets which have 0-more stocks to fill.
remove.Add(symbol);
}
}
//If there are any decrease holdings order process them first:
foreach (var symbol in delta.Keys) {
deltaQuantity = delta[symbol];
if (!IncreaseHoldings(symbol, delta[symbol])) {
orderId = _algorithm.MarketOrder(symbol, (int)deltaQuantity, false, "Decrease: " + symbol + " " + deltaQuantity);
if (orderId < 0) {
//Error placing order: adjust execution...
_algorithm.Error("DECREASE Order Error: " + orderId + " " + symbol + " Quantity:" + deltaQuantity);
}
}
}
//After processed the decrease of holdings, send the increase of holdings:
foreach (var symbol in delta.Keys) {
deltaQuantity = delta[symbol];
if (IncreaseHoldings(symbol, delta[symbol])) {
orderId = _algorithm.MarketOrder(symbol, (int)deltaQuantity, false, "Increase: " + symbol + " " + deltaQuantity);
if (orderId < 0) {
//Error placing order: adjust execution...
_algorithm.Error("INCREASE Order Error: " + orderId + " " + symbol + " Quantity:" + deltaQuantity);
}
}
}
//Strip the stocks already filled:
foreach (var symbol in remove) {
_target.Remove(symbol);
}
}
/// <summary>
/// Using the supplied portfolio targets execute the trades when stddeviation is ideal.
/// </summary>
private void ExecuteStandardDeviation() {
var badTick = false;
decimal deltaQuantity = 0;
var delta = new Dictionary<string, decimal>();
var remove = new List<string>();
var decreaseHoldings = false;
//Update standard deviation queue:
foreach (var kvp in _prices) {
var symbol = kvp.Key;
var price = Convert.ToDouble(kvp.Value.Close);
if (!_priceQueue.ContainsKey(symbol)) {
_priceQueue.Add(symbol, new FixedLengthQueue<double>(_devWindowPeriod));
}
//Enqueue new data:
_priceQueue[symbol].Enqueue(price);
}
//Only do analysis once we have sufficient data:
if (_devSampleCount < _devWindowPeriod) {
_devSampleCount++; return;
}
//Calculate current deviations from mean:
foreach (var kvp in _prices) {
var symbol = kvp.Key;
var price = Convert.ToDouble(kvp.Value.Close);
if (!_deviations.ContainsKey(symbol)) {
_deviations.Add(symbol, 0);
_deviationsStatistics.Add(symbol, new RunningStatistics());
}
_deviationsStatistics[symbol] = new RunningStatistics(_priceQueue[symbol].ToList());
//Update the standard deviation for this symbol: filter anything too extreme as fake tick.
var deviation = (price - _deviationsStatistics[symbol].Mean) / _deviationsStatistics[symbol].StandardDeviation;
if (Math.Abs(deviation) < _extremePoint) {
_deviations[symbol] = deviation;
} else {
badTick = true;
}
}
//Filter out bad ticks:
if (badTick) return;
//Find the difference in number target to holdings:
foreach (string symbol in _target.Keys) {
var total = _algorithm.Portfolio.TotalHoldingsValue + _algorithm.Portfolio.Cash * _algorithm.Securities[symbol].Leverage;
var price = _algorithm.Securities[symbol].Price;
//2. Difference between our target % and our current holdings: (relative +- number).
decimal deltaValue = (total * _target[symbol]) - _algorithm.Portfolio[symbol].HoldingsValue;
//Potential divide by zero error for zero prices assets.
if (Math.Abs(_algorithm.Securities[symbol].Price) > 0) {
//3. Now rebalance the symbol requested:
deltaQuantity = Math.Floor(deltaValue / _algorithm.Securities[symbol].Price);
}
//Determine if we need to place an order: if transaction volume more than $500. $1 fee on 1 share @ $25 trade is silly.
if (Math.Abs(deltaQuantity) > 0 && (price * Math.Abs(deltaQuantity) > 500)) {
delta.Add(symbol, deltaQuantity);
if (!IncreaseHoldings(symbol, deltaQuantity)) decreaseHoldings = true;
} else {
//Remove the targets which have 0-more stocks to fill.
remove.Add(symbol);
}
}
//If there are any decrease holdings order process them first:
foreach (var symbol in delta.Keys) {
deltaQuantity = delta[symbol];
if (!IncreaseHoldings(symbol, deltaQuantity)) {
if ((deltaQuantity > 0 && _deviations[symbol] < _buyPoint) || (deltaQuantity < 0 && _deviations[symbol] > _sellPoint)) {
_algorithm.MarketOrder(symbol, (int)deltaQuantity, false, "Decrease: " + symbol + " " + deltaQuantity);
}
}
}
//If there are any decrease holdings commands outstanding, process them first; don't run increase holdings.
if (!decreaseHoldings) {
//After processed the decrease of holdings, send the increase of holdings:
foreach (var symbol in delta.Keys) {
deltaQuantity = delta[symbol];
if (IncreaseHoldings(symbol, deltaQuantity)) {
if ((deltaQuantity > 0 && _deviations[symbol] < _buyPoint) || (deltaQuantity < 0 && _deviations[symbol] > _sellPoint)) {
_algorithm.MarketOrder(symbol, (int)deltaQuantity, false, "Increase: " + symbol + " " + deltaQuantity);
}
}
}
}
}
/// <summary>
/// Return true if the order would increase the holdings (long/short) of the symbol.
/// </summary>
private bool IncreaseHoldings(string symbol, decimal deltaQuantity) {
var increaseHoldings = false;
if (_algorithm.Portfolio.ContainsKey(symbol)) {
if ((_algorithm.Portfolio[symbol].IsLong && deltaQuantity > 0) || (_algorithm.Portfolio[symbol].IsShort && deltaQuantity < 0)) {
increaseHoldings = true;
}
if (_algorithm.Portfolio[symbol].Quantity == 0) {
increaseHoldings = true;
}
} else {
_algorithm.Error("IncreaseHoldings(): Symbol not found in portfolio");
}
return increaseHoldings;
}
}
} // End of RV Fund:
}using System;
using System.Collections.Generic;
using QuantConnect.Algorithm;
using QuantConnect.Data.Market;
namespace QuantConnect {
/// <summary>
/// QuantConnect QuantFramework Algorithm
///
/// Exit Management Module:
///
/// </summary>
public partial class QCUQuantFramework : QCAlgorithm {
/// <summary>
/// Exit Management Module:
/// </summary>
public class ModuleExit {
/********************************************************
* PRIVATE VARIABLES
*********************************************************/
private QCUQuantFramework _algorithm;
private ExitTechnique _technique;
/********************************************************
* PUBLIC PROPERTIES
*********************************************************/
/********************************************************
* PUBLIC CONSTRUCTOR
*********************************************************/
/// <summary>
/// Initialize the Exit Strategy Manager:
/// </summary>
/// <param name="algorithm">Algorithm instance</param>
public ModuleExit(QCUQuantFramework algorithm, ExitTechnique technique = ExitTechnique.Momentum) {
this._algorithm = algorithm;
this._technique = technique;
}
/********************************************************
* PUBLIC METHODS
*********************************************************/
/// <summary>
/// Scan the portfolio holdings for exit opportunities:
/// </summary>
public void Scan(TradeBars prices, Dictionary<Symbol, PortfolioTarget> targets) {
try {
//Based on set exit technique, scan and apply
switch (_technique) {
//No exit system (portfolio algorithms)
case ExitTechnique.None:
break;
}
} catch (Exception err) {
_algorithm.Error("ExitManager.Scan(): " + err.Message);
}
}
}
} // End of QCU QuantFramework
} // End of QuantConnect Namespaceusing System;
using QuantConnect.Algorithm;
namespace QuantConnect {
/// <summary>
/// QuantConnect QuantFramework Algorithm
///
/// Notification Management Module:
///
/// </summary>
public partial class QCUQuantFramework : QCAlgorithm {
/// <summary>
/// Notification Module:
/// </summary>
public class ModuleNotify {
/********************************************************
* PRIVATE VARIABLES
*********************************************************/
private QCUQuantFramework _algorithm;
private string _defaultToEmail = "";
private string _defaultPhoneNumber = "";
/********************************************************
* PUBLIC PROPERTIES
*********************************************************/
/********************************************************
* PUBLIC CONSTRUCTOR
*********************************************************/
/// <summary>
/// Initialize the Notification Manager:
/// </summary>
/// <param name="algorithm">Algorithm instance</param>
public ModuleNotify(QCUQuantFramework algorithm, string toEmail, string phoneNumber) {
this._algorithm = algorithm;
this._defaultToEmail = toEmail;
this._defaultPhoneNumber = phoneNumber;
}
/********************************************************
* PUBLIC METHODS
*********************************************************/
/// <summary>
/// Send an email to the notification addresses
/// </summary>
/// <param name="message"></param>
public void Send(string message, string toEmail = "", string ccEmail = "") {
try {
//Send Email
if (toEmail == "") toEmail = _defaultToEmail;
} catch (Exception err) {
_algorithm.Error("ModuleNotify.Send(): " + err.Message);
}
}
/// <summary>
/// Send a SMS to this phone number
/// </summary>
/// <param name="phoneNumber"></param>
public void SMS(string message, string phoneNumber = "") {
try {
//Send SMS
if (phoneNumber == "") phoneNumber = _defaultPhoneNumber;
} catch (Exception err) {
_algorithm.Error("ModuleNotify.SMS(): " + err.Message);
}
}
}
} // End of QCU QuantFramework
} // End of QuantConnect Namespaceusing System;
using System.Collections.Generic;
using QuantConnect.Algorithm;
using QuantConnect.Data.Market;
namespace QuantConnect {
/// <summary>
/// QuantConnect QuantFramework Algorithm
///
/// Risk Management Module:
///
/// </summary>
public partial class QCUQuantFramework : QCAlgorithm {
/// <summary>
/// Risk Management Module:
/// </summary>
public class ModuleRisk {
/********************************************************
* PRIVATE VARIABLES
*********************************************************/
private QCUQuantFramework _algorithm;
/********************************************************
* PUBLIC PROPERTIES
*********************************************************/
/********************************************************
* PUBLIC CONSTRUCTOR
*********************************************************/
/// <summary>
/// Initialize the Risk Manager:
/// </summary>
/// <param name="algorithm">Algorithm instance</param>
public ModuleRisk(QCUQuantFramework algorithm) {
this._algorithm = algorithm;
}
/********************************************************
* PUBLIC METHODS
*********************************************************/
/// <summary>
/// Analyse the list of directives, generate a quantity position size adjusting for market volatility
/// </summary>
/// <param name="directives">Directives to transfor.</param>
public void Analyse(TradeBars prices, Dictionary<Symbol, PortfolioTarget> targets) {
try {
//Control the total exposure:
//
// NOP.
//
} catch (Exception err) {
_algorithm.Error("RiskModule.Analyse(): " + err.Message);
}
}
}
} // End of QCU QuantFramework
} // End of QuantConnect Namespaceusing System.Globalization;
using System.Collections.Concurrent;
using QuantConnect.Algorithm;
using QuantConnect.Data;
using System;
namespace QuantConnect {
/// <summary>
/// QuantConnect QuantFramework Algorithm
///
/// Initialization and Parameters:
///
/// </summary>
public partial class QCUQuantFramework : QCAlgorithm {
/// <summary>
/// Algorithm Parameters:
/// </summary>
public static class FundParameters {
/// Total Assets Under Management:
public static decimal TotalFundAssets = 250000;
/// Maximum Allocation Per Algorithm
public static decimal AlgorithmMaximumAllocation = 50000;
}
/// <summary>
/// Strategy Risk Parameters:
/// </summary>
public static class RiskParameters {
/// Any position we take, set the maximum allowable risk.
public static decimal RiskPerTrade = 0.18m; // 15%
}
/// <summary>
/// Universe Selection Criteria
/// </summary>
public static class UniverseSelection {
//10 Days Analysis Before Filtering Universe:
public static decimal MinimumAnalysisPeriod = 10;
//Other ideal parameters if we had data:
//public static decimal MinimumMarketCapitalization = 0; etc
}
/// <summary>
/// Contact Settings for the Algorithm Notifier
/// </summary>
public static class Contacts {
/// Primary Contact Email Addresses
public static string ToEmail = "fameoflight@gmail.com";
/// Primary SMS Notification
public static string PhoneNumber = "415-355-4946";
}
/// <summary>
/// Portfolio Target from a signal decision:
/// </summary>
public class PortfolioTarget {
/// Symbol to Trade:
public Symbol Symbol;
/// Direction Signal: -1 to +1
public decimal Signal;
public PortfolioTarget(Symbol symbol, decimal signal = 1) {
this.Symbol = symbol;
this.Signal = signal;
}
}
/// <summary>
/// Asset industry categories:
/// </summary>
public enum Industry {
All,
Bonds,
BasicMaterials,
CapitalGoods,
Consumer,
Energy,
Financial,
Services,
Transportation,
Technology,
Healthcare,
RealEstate,
Utilities
}
/// <summary>
/// Property group of an asset - Symbol, Volume, Industry, PE.. etc. For expansion later:
/// </summary>
public class Asset {
/// Symbol of this asset:
public Symbol Symbol;
/// Asset Industry Catgegory:
public Industry Industry;
///Volume of the asset in millions:
public decimal Volume;
/// 20 Day Average Closing Price of the Asset:
public decimal Price;
/// Initialise the Asset Property Group:
public Asset(Symbol symbol, Industry industry, decimal price, decimal volume) {
this.Symbol = symbol;
this.Industry = industry;
this.Volume = 0;
this.Price = 0;
}
}
/// <summary>
/// Stoploss / exit technique to apply
/// </summary>
public enum ExitTechnique {
/// No exit technique. Do not interfere.
None,
//Mebane Faber 10 Month Average Exit.
Momentum,
/// Exit immediately after achieving a prefixed gain
FixedGain,
/// Use a rolling stoploss immediately after taking position.
FixedRollingStoploss,
/// Rolling stoploss which increases closing speed exponentially.
ParabolicRollingStoploss,
/// Sell 20% of holdings with each 0.1% return achieved.
FractionalProfitTaking
}
/// <summary>
/// Determine execution technique for the algorithm:
/// </summary>
public enum ExecutionTechnique {
/// Execute immediately, as fast as possible.
Immediate,
/// Volume weighted average price execution, wait for VWAP price or better before executing.
VWAP,
/// Wait for negative stddev before ordering (price favourable).
StandardDeviation
}
} // End of RV Fund:
/// <summary>
/// Queue which automatically dequeues old data.
/// </summary>
public class FixedLengthQueue<T> : ConcurrentQueue<T> {
public int Size { get; private set; }
public FixedLengthQueue(int size) {
Size = size;
}
public new void Enqueue(T obj) {
base.Enqueue(obj);
lock (this) {
while (base.Count > Size) {
T outObj;
base.TryDequeue(out outObj);
}
}
}
}
/// <summary>
/// Custom imported data -- VIX indicator:
/// </summary>
public class VIX : BaseData {
public decimal Open = 0;
public decimal High = 0;
public decimal Low = 0;
public decimal Close = 0;
public VIX() { this.Symbol = Symbol.Create("VIX", SecurityType.Base, Market.USA); }
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLive) {
return new SubscriptionDataSource("https://www.quandl.com/api/v1/datasets/YAHOO/INDEX_VIX.csv?trim_start=2000-01-01&trim_end=2016-10-27&sort_order=asc&exclude_headers=true", SubscriptionTransportMedium.RemoteFile);
}
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLive) {
VIX fear = new VIX();
//try
//{
//Date Open High Low Close Volume Adjusted Close
//10/27/2014 17.24 17.87 16 16.04 0 16.04
string[] data = line.Split(',');
fear.Time = DateTime.ParseExact(data[0], "yyyy-MM-dd", CultureInfo.InvariantCulture);
fear.Open = Convert.ToDecimal(data[1]); fear.High = Convert.ToDecimal(data[2]);
fear.Low = Convert.ToDecimal(data[3]); fear.Close = Convert.ToDecimal(data[4]);
fear.Value = fear.Close;
//}
//catch
//{ }
return fear;
}
} // End of VIX
} // End of QuantConnect Namespaceusing System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using QuantConnect.Algorithm;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators.CandlestickPatterns;
namespace QuantConnect {
/// <summary>
///
/// QuantConnect University - Quant-Framework Implementation
///
/// Basic algorithm framework implementation to design a robust, thorough and
/// thoughtful algorithm which can meet the challenges of live trading
///
/// </summary>
public partial class QCUQuantFramework : QCAlgorithm {
private Symbol _cashAsset = QuantConnect.Symbol.Create("AGG", SecurityType.Equity, Market.USA);
public Symbol CashAsset {
get {
return _cashAsset;
}
}
/********************************************************
* PRIVATE VARIABLES
*********************************************************/
/// <summary>
/// Prices of all Assets Stores Rolling Forward:
/// </summary>
private TradeBars _prices = new TradeBars();
/// <summary>
/// Universe of symbols for today:
/// </summary>
private List<Symbol> _universe = new List<Symbol>();
/********************************************************
* PUBLIC PROPERTIES
*********************************************************/
/// <summary>
/// Module 1: Screen assets daily to match criteria; generate list of matching assets.
/// </summary>
public ModuleAssets AssetManager;
/// <summary>
/// Module 2: Generate alpha / signals based on desired behaviour. Signals from -1 to +1.
/// </summary>
public ModuleAlpha AlphaManager;
/// <summary>
/// Module 3: Manage Net Portfolio Cash Risk to ensure maximum 1% Exposed.
/// </summary>
public ModuleRisk RiskManager;
/// <summary>
/// Module 4: Factoring in the signal strength, apply stop loss techniques to control the position exit.
/// </summary>
public ModuleExit ExitManager;
/// <summary>
/// Module 5: Given a Desired Portfolio; Execute trades to reach this portfolio in the optimial manner possible
/// </summary>
public ModuleExecute ExecutionManager;
/// <summary>
/// Module 6: Send instant email/SMS notifications on issuing trades.
/// </summary>
public ModuleNotify NotificationManager;
/********************************************************
* PUBLIC METHODS
*********************************************************/
/// <summary>
/// Initialize algorithm and create instances of all the portfolio modules
/// </summary>
public override void Initialize() {
SetWarmUp(TimeSpan.FromDays(45));
//Backtest Range:
// Make sure you check the start dates of the assets you trade.
SetStartDate(2015, 1, 1);
SetEndDate(DateTime.Now.Date.AddDays(-1));
//Set Cash to $250k
SetCash(FundParameters.AlgorithmMaximumAllocation);
//Initalize Algorithm-A Modules:
AssetManager = new ModuleAssets(this);
// Analyse Generation of New Positions:
AlphaManager = new ModuleAlpha(this);
// Monitor the Risk Profile
RiskManager = new ModuleRisk(this);
// Analysis of Exit Positions:
ExitManager = new ModuleExit(this);
// Time and Split the Orders:
ExecutionManager = new ModuleExecute(this, ExecutionTechnique.StandardDeviation);
// Send Notifications of Positions:
NotificationManager = new ModuleNotify(this, Contacts.ToEmail, Contacts.PhoneNumber);
//Add custom data:
AddData<VIX>("VIX", Resolution.Minute);
}
/// <summary>
/// New Data Event: Process new data signal into the modules:
/// </summary>
/// <param name="data"></param>
public void OnData(TradeBars bars) {
//1. Initialize: only continue when prices completely full:
if (!UpdatePrices(bars)) return;
if (!this.IsWarmingUp) {
// 2. Update the Modules:
var targets = AlphaManager.Scan(_prices, _universe);
if (targets.Count > 0) {
Debug(string.Format("Alpha Generated {0} universe {1} price {2}", targets.Count, _universe.Count, _prices.Count));
}
// 3. Quantify directives into risk-adjusted positions:
RiskManager.Analyse(_prices, targets);
// 4. Before Sending to Execution Manager, Scan for Exit Signal:
ExitManager.Scan(_prices, targets);
// 5. Issue Quantified Directives to Execution Manager:
ExecutionManager.SetPortfolioTarget(targets);
// 6. Issue Trade Orders to Actually Create Portfolio
ExecutionManager.Execute(_prices);
}
}
/// <summary>
/// New Data Event: VIX daily pricing:
/// </summary>
public void OnData(VIX data) {
TradeBar vixBar = new TradeBar();
vixBar.Open = data.Open;
vixBar.High = data.High;
vixBar.Low = data.Low;
vixBar.Close = data.Close;
vixBar.Value = data.Value;
vixBar.Time = data.Time;
_prices[data.Symbol.ToString()] = vixBar;
}
public override void OnEndOfDay(Symbol symbol) {
if (_prices.ContainsKey(symbol)) {
AssetManager.UpdateAssetProperties(symbol, _prices[symbol.ToString()]);
}
_universe = AssetManager.UpdateUniverse();
}
/// <summary>
/// Update the price store:
/// </summary>
private bool UpdatePrices(TradeBars bars) {
foreach (var bar in bars.Values) {
// 1.1 Record the prices for future reference
_prices[bar.Symbol.ToString()] = bar;
}
Debug(string.Format("Prices {0}", _prices.Count));
//return (_prices.Count == Portfolio.Count);
return _prices.Count > 0;
}
public override void OnSecuritiesChanged(SecurityChanges changes) {
AssetManager.OnSecuritiesChanged(changes);
_universe = AssetManager.UpdateUniverse();
AlphaManager.UpdateAssets(_universe);
List<Symbol> obsolteSymbols = new List<Symbol>();
foreach (var symbol in _prices.Keys) {
if (!_universe.Contains(symbol)) {
obsolteSymbols.Add(symbol);
}
}
foreach (var symbol in obsolteSymbols) {
_prices.Remove(symbol);
}
}
} // End of QCU QuantFramework
} // End of QuantConnect Namespace