| Overall Statistics |
|
Total Trades 2029 Average Win 0.43% Average Loss -0.48% Compounding Annual Return 8.508% Drawdown 22.100% Expectancy 0.078 Net Profit 50.453% Sharpe Ratio 0.507 Loss Rate 43% Win Rate 57% Profit-Loss Ratio 0.88 Alpha 0.036 Beta 0.389 Annual Standard Deviation 0.155 Annual Variance 0.024 Information Ratio -0.188 Tracking Error 0.169 Treynor Ratio 0.202 Total Fees $13345.04 |
using System.Collections.Concurrent;
namespace QuantConnect
{
public class RsiEmaCrossUniverseSelectionAlgorithm : QCAlgorithm
{
private const int Count = 10;
private const decimal Tolerance = 1.01m;
// holds our coarse fundamental indicators by symbol
private readonly ConcurrentDictionary<Symbol, SelectionData> _averages = new ConcurrentDictionary<Symbol, SelectionData>();
// class used to improve readability of the coarse selection function
private class SelectionData
{
public readonly ExponentialMovingAverage Fast;
public readonly ExponentialMovingAverage Slow;
public readonly RelativeStrengthIndex Rsi;
public SelectionData()
{
Fast = new ExponentialMovingAverage(100);
Slow = new ExponentialMovingAverage(300);
Rsi = new RelativeStrengthIndex(30);
}
// computes an object score of how much large the fast is than the slow
public decimal ScaledDelta
{
get { return (Fast - Slow) / ((Fast + Slow)/2m); }
}
// updates the RSI30 EMA100 and EMA300 indicators, returning true when they're both ready
public bool Update(DateTime time, decimal value)
{
return Rsi.Update(time, value) && Fast.Update(time, value) && Slow.Update(time, value);
}
}
public override void Initialize()
{
UniverseSettings.Leverage = 2.0m;
UniverseSettings.Resolution = Resolution.Daily;
SetStartDate(2010, 01, 01);
SetEndDate(2015, 01, 01);
SetCash(100000);
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.Price)
// only pick symbols who RSI less than 30
where avg.Rsi < 30
// only pick symbols who have their 50 day ema over their 100 day ema
where avg.Fast > avg.Slow * Tolerance
// prefer symbols with a larger delta by percentage between the two averages
orderby avg.ScaledDelta descending
// we only need to return the symbol and return 'Count' symbols
select cf.Symbol).Take(Count);
});
}
public override void OnData(Slice data) {
//
}
public override void OnSecuritiesChanged(SecurityChanges changes) {
foreach (var security in changes.RemovedSecurities) {
if (security.Invested) {
Liquidate(security.Symbol);
}
}
foreach (var security in changes.AddedSecurities) {
SetHoldings(security.Symbol, 1m / Count);
}
}
}
}