| Overall Statistics |
|
Total Trades 90 Average Win 0.63% Average Loss -0.74% Compounding Annual Return 41.182% Drawdown 9.800% Expectancy 0.543 Net Profit 41.182% Sharpe Ratio 2.715 Probabilistic Sharpe Ratio 93.223% Loss Rate 17% Win Rate 83% Profit-Loss Ratio 0.85 Alpha 0.345 Beta -0.049 Annual Standard Deviation 0.125 Annual Variance 0.016 Information Ratio 1.323 Tracking Error 0.177 Treynor Ratio -7.01 Total Fees $125.95 |
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Orders;
using QuantConnect.Securities;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp
{
public class TachyonOptimizedRegulators : QCAlgorithm
{
private PriceIndexUniverseSelection _universeSelection;
private DateTime lastRebalance;
public List<Symbol> symbols = new List<Symbol>();
public override void Initialize()
{
SetStartDate(2016, 1, 1);
SetEndDate(2017, 1, 1);
SetCash(100000);
UniverseSettings.Resolution = Resolution.Daily;
SetUniverseSelection(_universeSelection = new PriceIndexUniverseSelection());
AddAlpha(new PriceIndexAlphaModel());
SetPortfolioConstruction(new PriceIndexPortfolioConstruction());
SetExecution(new PriceIndexExecutionModel());
AddRiskManagement(new SpyRedCrossRiskManagementModel(this));
Rebalance();
}
public override void OnData(Slice slice)
{
if (Time > lastRebalance.AddMonths(6))
{
Rebalance();
}
}
public void Rebalance()
{
lastRebalance = Time;
if (Portfolio.Invested)
{
Debug(Time + ": Liquidating portfolio!");
Liquidate();
}
_universeSelection.Rebalance();
}
public override void OnEndOfAlgorithm()
{
Liquidate();
}
public class PriceIndexUniverseSelection : FundamentalUniverseSelectionModel
{
private bool rebalance = false;
public PriceIndexUniverseSelection() : base(true, null, null)
{ }
public override IEnumerable<Symbol> SelectCoarse(QCAlgorithm algo, IEnumerable<CoarseFundamental> coarse)
{
TachyonOptimizedRegulators myAlgo = (TachyonOptimizedRegulators)algo;
if (!rebalance)
return algo.Universe.Unchanged;
var stocks = (from c in coarse
where c.DollarVolume > 300000 &&
c.DollarVolume < 2000000 &&
c.Price > 5
where c.HasFundamentalData
orderby c.DollarVolume descending
select c.Symbol).Take(500);
return stocks;
}
public override IEnumerable<Symbol> SelectFine(QCAlgorithm algo, IEnumerable<FineFundamental> fine)
{
TachyonOptimizedRegulators myAlgo = (TachyonOptimizedRegulators)algo;
if (!rebalance)
return algo.Universe.Unchanged;
myAlgo.symbols.Clear();
var sortedByPriceIndex = from stock in fine
where stock.MarketCap < 1000000000
let history = algo.History<TradeBar>(stock.Symbol, new TimeSpan(180, 0, 0), Resolution.Daily)
where history.Count() > 0
let priceIndex = history.Last().Close - history.First().Close
orderby priceIndex
descending
select stock;
int numberOfStocksToPick = (int)Math.Round(sortedByPriceIndex.Count() * 0.2);
var highestPriceIndexStocks = sortedByPriceIndex.Take(numberOfStocksToPick);
rebalance = false;
myAlgo.symbols = (from x in highestPriceIndexStocks
orderby x.ValuationRatios.PBRatio
select x.Symbol).Take(30).ToList();
algo.Debug(myAlgo.Time + ": Succesfully chose " + myAlgo.symbols.Count + " new stocks!");
return myAlgo.symbols;
}
public void Rebalance()
{
rebalance = true;
}
}
public class PriceIndexAlphaModel : IAlphaModel
{
public void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) { }
public IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
List<Insight> insights = new List<Insight>();
TachyonOptimizedRegulators myAlgo = (TachyonOptimizedRegulators)algorithm;
foreach (var symbol in myAlgo.symbols)
{
insights.Add(new Insight(symbol, new TimeSpan(1, 0, 0, 0, 0), InsightType.Price, InsightDirection.Up));
}
return insights;
}
}
public class PriceIndexPortfolioConstruction : PortfolioConstructionModel
{
public override IEnumerable<IPortfolioTarget> CreateTargets(QCAlgorithm algorithm, Insight[] insights)
{
TachyonOptimizedRegulators myAlgo = (TachyonOptimizedRegulators)algorithm;
List<IPortfolioTarget> targets = new List<IPortfolioTarget>();
int stocksToBuy = (from x in insights
where x.Direction == InsightDirection.Up
select x).Count();
if (stocksToBuy > 0)
{
decimal percentToBuy = Convert.ToDecimal((float)1 / (float)stocksToBuy);
foreach (var insight in insights)
{
if (insight.Direction == InsightDirection.Up && !myAlgo.Portfolio[insight.Symbol].Invested)
{
//Indicated to buy
targets.Add(PortfolioTarget.Percent(algorithm, insight.Symbol, percentToBuy));
}
// This will be triggered by risk management
else if (insight.Direction == InsightDirection.Down && myAlgo.Portfolio[insight.Symbol].Invested)
{
//Indicated to liquidate
targets.Add(new PortfolioTarget(insight.Symbol, 0));
}
}
}
return targets;
}
}
public class PriceIndexExecutionModel : ExecutionModel
{
public override void Execute(QCAlgorithm algorithm, IPortfolioTarget[] targets)
{
foreach (var target in targets)
{
if (target.Quantity > 0)
{
if (algorithm.Transactions.GetOpenOrders(target.Symbol).Count == 0 && !algorithm.Portfolio[target.Symbol].Invested)
{
algorithm.MarketOrder(target.Symbol, target.Quantity);
}
}
else
{
if (algorithm.Portfolio[target.Symbol].Invested)
{
algorithm.Liquidate(target.Symbol);
}
}
}
}
}
public class SpyRedCrossRiskManagementModel : RiskManagementModel
{
private ExponentialMovingAverage _signal;
private Security _spy;
public SpyRedCrossRiskManagementModel(QCAlgorithm algo)
{
_spy = algo.AddEquity("SPY", Resolution.Daily);
_signal = new ExponentialMovingAverage(200);
algo.RegisterIndicator(_spy.Symbol, _signal, Resolution.Daily);
}
public override IEnumerable<IPortfolioTarget> ManageRisk(QCAlgorithm algo, IPortfolioTarget[] targets)
{
List<IPortfolioTarget> newTargets = new List<IPortfolioTarget>();
var spyClose = algo.Securities["SPY"].Close;
if (_signal.IsReady && spyClose < _signal)
{
foreach (var target in targets)
{
newTargets.Add(new PortfolioTarget(target.Symbol, 0));
}
algo.Debug(algo.Time + ": SPY is below minimum price signal - restricting trade!");
}
return newTargets;
}
}
}
}