| Overall Statistics |
|
Total Trades 51 Average Win 0.21% Average Loss -0.24% Compounding Annual Return -1.018% Drawdown 9.000% Expectancy -0.655 Net Profit -1.121% Sharpe Ratio -0.071 Loss Rate 82% Win Rate 18% Profit-Loss Ratio 0.90 Alpha -0.031 Beta 0.348 Annual Standard Deviation 0.076 Annual Variance 0.006 Information Ratio -0.773 Tracking Error 0.103 Treynor Ratio -0.016 Total Fees $51.00 |
using System;
using System.Collections.Concurrent;
using System.Linq;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
namespace QuantConnect.Algorithm.CSharp
{
// mittelwert_neu = mittelwert_bisher - (mittelwert_bisher - neuer_wert)/anzahl_werte
/// <summary>
/// tbd
/// </summary>
public class UW_Simplify_V3 : QCAlgorithm
{
private Symbol _spy = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
private SecurityChanges _changes = SecurityChanges.None;
private DateTime TestDate = new DateTime(2016,10,22);
//private readonly Dictionary<Symbol, SymbolData> Data = new Dictionary<Symbol, SymbolData>();
// holds our coarse fundamental indicators by symbol
private readonly ConcurrentDictionary<Symbol, SelectionData> _averages = new ConcurrentDictionary<Symbol, SelectionData>();
const decimal Tolerance = 0.01m;
private const int Count = 30;
private const decimal TargetPercent = 0.1m;
private const decimal tpPercent = 0.05m;
Dictionary<Symbol, SymbolData> MySymbolData = new Dictionary<Symbol, SymbolData>();
// class used to improve readability of the coarse selection function
private class SelectionData
{
public readonly ExponentialMovingAverage Fast;
public readonly ExponentialMovingAverage Slow;
public readonly ExponentialMovingAverage Slowest;
public SelectionData()
{
Fast = new ExponentialMovingAverage(20);
Slow = new ExponentialMovingAverage(30);
Slowest = new ExponentialMovingAverage(100);
}
// 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 EMA50 and EMA100 indicators, returning true when they're both ready
public bool Update(DateTime time, decimal value)
{
return Fast.Update(time, value) && Slow.Update(time, value) && Slowest.Update(time, value);
}
}
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2015, 10, 07); //Set Start Date
SetEndDate(2016, 11, 11); //Set End Date
SetCash(25000); //Set Strategy Cash
// AddEquity("SPY", Resolution.Daily);
UniverseSettings.Resolution = Resolution.Daily;
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 have their price over their 200 day ema
where cf.Price > avg.Slowest
// only pick symbols who have their 50 day ema over their 200 day ema
where avg.Slow > avg.Slowest
// only pick symbols who have their 20 day ema over their 20 day ema
where avg.Fast> avg.Slow
// 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);
});
Debug(" End Init");
foreach (var added in _changes.AddedSecurities)
{
if (!MySymbolData.ContainsKey(added.Symbol))
{
MySymbolData.Add(added.Symbol, new SymbolData(added.Symbol, this));
Debug(" in Init added " + added.Symbol);
}
}
} // end Initialize
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice data)
{
if (!Portfolio.Invested)
{
SetHoldings(_spy, 1);
Debug("Purchased Stock");
}
if (_changes == SecurityChanges.None) return;
foreach (var Stock in MySymbolData.Values)
{
if (data.ContainsKey(Stock.Symbol)) return;
if (IsWarmingUp) return;
// Stock.Update(Stock.Security, Stock.Security.Time);
// Stock.lSMA.Update(data.EndTime, data.Close);
Debug(" >> " + Stock.Security + " " + Stock.Security.Price + " " + Stock.hSMA + " " + Stock.lSMA);
if ( Portfolio.Count < 5)
{
if ( Stock.Security.Price > Stock.hSMA )
{
Log("BUY >> " + Stock.Security.Price);
Debug("BUY >> " + Stock.Security.Price);
SetHoldings(Stock.Symbol, 0.5m);
var takeProfit = Stock.Security.Price*tpPercent;
LimitOrder(Stock.Symbol, - Stock.Quantity, takeProfit);
}
if (Stock.Quantity > 0 && Stock.Security.Price <= Stock.lSMA)
{
Log("SELL >> " + Stock.Security.Price);
Debug("SELL >> " + Stock.Security.Price);
Liquidate(Stock.Symbol);
}
}
}
// liquidate securities removed from our universe
foreach (var security in _changes.RemovedSecurities)
{
if (security.Invested)
{
Liquidate(security.Symbol);
}
}
// we'll simply go long each security we added to the universe
foreach (var security in _changes.AddedSecurities)
{
SetHoldings(security.Symbol, 1);
}
foreach (var security in _changes.AddedSecurities) {
if (Time.Date == new DateTime(2016,10,13) )
Debug("1 Symbol= " + Time.ToShortDateString() + " " + security.Symbol.ToString() + " " );
}
} // end OnData
public override void OnSecuritiesChanged(SecurityChanges changes)
{
_changes = changes;
Debug(Time.Date.ToShortDateString() + " 2 Number=" + _changes.AddedSecurities.Count.ToString() );
foreach (var security in _changes.AddedSecurities)
{
Debug("Added " + security.Symbol);
if (!MySymbolData.ContainsKey(security.Symbol))
{
MySymbolData.Add(security.Symbol, new SymbolData(security.Symbol, this));
Debug("Added to Data -> " + security.Symbol);
}
}
foreach (var security in _changes.RemovedSecurities)
{
Debug("Removed " + security.Symbol);
}
} // end OnSecuritiesChanged
} // end class
/*
You will need to create a class similar to SelectionData, say SymbolData,
and create a dictionary to hold its values Dictionary<Symbol, SymbolData>
to save the SMA of High and Low to be used as trading signal.
*/
class SymbolData
{
public string Symbol;
private const int hPeriods = 8;
public int rollingWindowSize = 1;
public readonly Security Security;
public int Quantity
{
get { return (int)Security.Holdings.Quantity; }
}
public readonly Identity Close;
public readonly SimpleMovingAverage hSMA;
public readonly SimpleMovingAverage lSMA;
public readonly RollingWindow<TradeBar> lastDay;
public SymbolData(string symbol, QCAlgorithm algorithm)
{
Symbol = symbol;
Security = algorithm.Securities[symbol];
Close = algorithm.Identity(symbol);
hSMA = algorithm.SMA(symbol, hPeriods, Resolution.Daily, Field.High);
lSMA = algorithm.SMA(symbol, hPeriods, Resolution.Daily, Field.Low);
lastDay = new RollingWindow<TradeBar>(rollingWindowSize);;
}
public bool Update(CoarseFundamental coarse)
{
lSMA.Update(coarse.EndTime, coarse.Value);
return hSMA.Update(coarse.EndTime, coarse.Value );
}
public bool IsReady
{
get { return Close.IsReady && hSMA.IsReady && lSMA.IsReady && lastDay.IsReady; }
}
} // end class
} // end namespace