| Overall Statistics |
|
Total Trades 1271 Average Win 0.56% Average Loss -0.32% Compounding Annual Return 134.851% Drawdown 11.000% Expectancy 0.435 Net Profit 135.952% Sharpe Ratio 2.367 Loss Rate 47% Win Rate 53% Profit-Loss Ratio 1.73 Alpha 0.485 Beta 21.027 Annual Standard Deviation 0.375 Annual Variance 0.141 Information Ratio 2.316 Tracking Error 0.375 Treynor Ratio 0.042 Total Fees $1347.66 |
using System;
using System.Collections.Concurrent;
using System.Linq;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Indicators.CandlestickPatterns;
namespace QuantConnect.Algorithm.CSharp
{
public class ShortTechnicalUniverseSelectionAlgorithm : QCAlgorithm
{
// tolerance to prevent bouncing
const decimal Tolerance = 0.01m;
private const int Count = 10;
// use Buffer+Count to leave a little in cash
private const decimal TargetPercent = -0.1m;
private SecurityChanges _changes = SecurityChanges.None;
// holds our coarse fundamental indicators by symbol
private readonly ConcurrentDictionary<Symbol, SelectionData> _averages = new ConcurrentDictionary<Symbol, SelectionData>();
public BollingerBands _eqBB;
public BollingerBands _irBB;
// class used to improve readability of the coarse selection function
private class SelectionData
{
public ExponentialMovingAverage Fast;
public ExponentialMovingAverage Slow;
public RelativeStrengthIndex _shortRSI;
public CandlestickPatterns _eveDoji;
public SelectionData()
{
_shortRSI = new RelativeStrengthIndex(14);
//_eveDoji = new CandlestickPatterns.EveningDojiStar(0.3m);
}
// updates the RSI and Technical indicators, returning true when they're ready
public bool Update(DateTime time, decimal value)
{
//return Fast.Update(time, value) && Slow.Update(time, value);
return _shortRSI.Update(time, value);
//return _eveDoji.Updaate(time, value);
}
}
public override void Initialize()
{
UniverseSettings.Leverage = 2.0m;
UniverseSettings.Resolution = Resolution.Daily;
SetStartDate(2018, 01, 01);
SetEndDate(2019, 01, 01);
//SetEndDate(DateTime.Now.Date.AddDays(-1));
SetCash(10*1000);
SetWarmup(200);
AddEquity("SPY", Resolution.Daily);
AddEquity("TLT", Resolution.Daily);
_eqBB = BB("SPY", 200, 1, MovingAverageType.Simple, Resolution.Daily);
_irBB = BB("TLT", 200, 1, MovingAverageType.Simple, Resolution.Daily);
//rebalance to simple long portfolio (75/25, 50/50, or 25/75) at the beginning of the week based on broad market technical info
Schedule.On(DateRules.WeekStart("SPY"), TimeRules.AfterMarketOpen("SPY", 10), () =>
{
RebalanceLong();
});
//trades a short portfolio on margin with an RSI screen and various CandlestickPatterns
AddUniverse(coarse =>
{
return (from cf in coarse
// grab th SelectionData instance for this symbol
let avg = _averages.GetOrAdd(cf.Symbol, sym => new SelectionData())
// Update returns true when the indicators are ready, so don't accept until they are
where avg.Update(cf.EndTime, cf.AdjustedPrice)
where cf.Symbol != "SPY"
where cf.Symbol != "TLT"
//filter by RSI
where avg._shortRSI > 80
where cf.Price > 5.0m
where cf.DollarVolume > 1 * 1000000
//where cf._eveDoji == True
// sort symbols with a larger delta by percentage between the two averages
orderby avg._shortRSI descending
// we only need to return the symbol and return 'Count' symbols
select cf.Symbol).Take(Count);
});
}
public void OnData(TradeBars data)
{
if (_changes == SecurityChanges.None) return;
// liquidate securities removed from our universe
foreach (var security in _changes.RemovedSecurities)
{
if (security.Invested && (security.Symbol != "SPY" || security.Symbol != "TLT"))
{
Liquidate(security.Symbol);
}
}
// we'll simply go short each security we added to the universe
foreach (var security in _changes.AddedSecurities)
{
SetHoldings(security.Symbol, TargetPercent);
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
_changes = changes;
}
public void RebalanceLong()
{
if (Securities["SPY"].Price > _eqBB.MiddleBand && Securities["TLT"].Price < _irBB.MiddleBand)
{
SetHoldings("SPY", 0.75);
SetHoldings("TLT", 0.25);
}
else if (Securities["SPY"].Price < _eqBB.MiddleBand && Securities["TLT"].Price > _irBB.MiddleBand)
{
SetHoldings("SPY", 0.25);
SetHoldings("TLT", 0.75);
}
else {
SetHoldings("SPY", 0.50);
SetHoldings("TLT", 0.50);
}
}
}
}