| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 |
namespace QuantConnect
{
public class FOREXBasicTemplateAlgorithm : QCAlgorithm
{
private AverageDirectionalIndex adx;
private SimpleMovingAverage SMA;
TradeBar EU5;
public override void Initialize()
{
SetStartDate(2016, 3, 1);
SetEndDate(2016, 3, 30);
SetCash(1000);
AddSecurity(SecurityType.Forex, "EURUSD", Resolution.Minute);
var minConsolidator = new TradeBarConsolidator(TimeSpan.FromMinutes(5));
SMA = new SimpleMovingAverage("SMA", 10);
//RegisterIndicator( , SMA, minConsolidator, x => x.Value);
minConsolidator.DataConsolidated += OnFiveMinutes;
SubscriptionManager.AddConsolidator("EURUSD", minConsolidator);
adx = new AverageDirectionalIndex(30);
}
private void OnFiveMinutes(object sender, TradeBar data)
{
EU5 = data;
adx.AddSample(EU5);
if (!adx.Ready) return;
Plot("ADX", adx.ADX);
Plot("+", adx.DMI_Pos);
Plot("-", adx.DMI_Neg);
if (!Portfolio.HoldStock)
{
//SetHoldings("EURUSD", 50, true);
//Debug("Buying EURUSD on " + Time.ToShortDateString());
}
}
}
} using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using QuantConnect.Securities;
using QuantConnect.Models;
using System.Linq;
namespace QuantConnect {
/* ADX Indicator - Average Directional Index is a complicated but powerful indicator.
*
* 1. Calculate the Directional Movements: +DM_t, -DM_t.
* 2. Find the Average Directional Movement: ADM_t
* 3. Calculate the Average True Range: ATR_t
* 4. Calculate the Directional Indexes: DI+_t, DI-_t,
* Directional Movement Index: DX_t,
* then Average Directional Movement Index! ADX_t
*
* Requires day to be divided into segments, periods and a running record kept of the previous value so the averages can be made.
*/
public class AverageDirectionalIndex {
//Public Result Access: Primary ADX Indicator
public decimal ADX {
get; private set;
}
//Public Result Access: DMI Positive:
public decimal DMI_Pos {
get; private set;
}
//Public Result Access: DMI Negative:
public decimal DMI_Neg {
get; private set;
}
//Public Result Access: Direction of the ADX Indicator:
public decimal Decision {
get; private set;
}
//Public Result Access: When indicator has sufficient data flags as true.
public bool Ready {
get; private set;
}
//Initialize
private ADXCacheItem indicatorMemory = new ADXCacheItem();
private decimal _expConst = 0;
private int _samplePeriods = 0;
private Candle _superCandle = new Candle();
private FixedLengthQueue<TradeBar> _rollingQueue = new FixedLengthQueue<TradeBar>(0);
// Constructor: Set the sample period:
public AverageDirectionalIndex(int samplePeriods) {
_expConst = (2m / (decimal)(samplePeriods + 1));
_samplePeriods = samplePeriods;
_rollingQueue = new FixedLengthQueue<TradeBar>(samplePeriods);
Ready = false;
}
/// <summary>
/// Calculate the ADX figure, return an indicator result.
/// </summary>
public decimal AddSample(TradeBar bar) {
//0. Save these samples in running OHLC candle until requested samplePeriod reached:
_rollingQueue.Enqueue(bar);
if (_rollingQueue.Count < _samplePeriods) return Decision;
//Create the bar on this rolling window:
var bars = _rollingQueue.ToList();
foreach (var queueBar in bars)
{
_superCandle.Update(bar);
}
//0. Define a result storage for this session.
ADXCacheItem current = new ADXCacheItem();
current.OHLC = _superCandle;
//0. If this is the first candle skip it and come back for second: to calc directional index can't be relative to 0.
if (!indicatorMemory.Set) {
current.Set = true;
indicatorMemory = current;
_superCandle = new Candle();
return Decision;
}
//1. Calculate the Directional Movements: store results back into current-variable class cache
GetDirectionalMovements(ref current);
//2. Find the Average Directional Movement.
GetAverageDirectionalMovements(ref current);
//3. Get the Average True Range:
GetAverageTrueRange(ref current);
//4. Get the Average Directional Movement Index ADX-t, and DI+, DI-
GetADX(ref current);
//Strong Trend is Present, and have at least X-min data
Decision = 0;
if (current.Adx > 40) {
//NOW! We have an ADX result, interpret it..
if (current.DmiPos > 40) {
Decision = 1;
} else if (current.DmiNeg > 40) {
Decision = -1;
}
}
//Save the results to publicly accessible properties.
ADX = current.Adx;
DMI_Neg = current.DmiNeg;
DMI_Pos = current.DmiPos;
//Update the indicator cache - store previous result between calls.
current.Set = true; Ready = true;
indicatorMemory = current;
_superCandle = new Candle();
return Decision;
}
/// <summary>
/// 1. Get the pure directional movements, in DM+, DM- Form.
/// </summary>
/// <param name="current">ADX Cache class for easy storing for next analysis session.</param>
private void GetDirectionalMovements(ref ADXCacheItem current) {
//Change from the previous period to now.
decimal deltaHigh = current.OHLC.High - indicatorMemory.OHLC.High;
decimal deltaLow = indicatorMemory.OHLC.Low - current.OHLC.Low;
//Allocate the Delta Movement.
if ((deltaHigh < 0 && deltaLow < 0) || (deltaHigh == deltaLow)) {
current.Dm_plus = 0;
current.Dm_neg = 0;
} else if (deltaHigh > deltaLow) {
current.Dm_plus = deltaHigh;
current.Dm_neg = 0;
} else if (deltaHigh < deltaLow) {
current.Dm_plus = 0;
current.Dm_neg = deltaLow;
}
}
/// <summary>
/// 2. Get the Exp Average of the directional movement indexs
/// </summary>
private void GetAverageDirectionalMovements(ref ADXCacheItem current) {
if (!Ready) {
//If this is the first run,
current.Adm_plus = current.Dm_plus;
current.Adm_neg = current.Dm_neg;
} else {
//This is not our first sample
current.Adm_plus = (current.Dm_plus * _expConst) + (indicatorMemory.Adm_plus * (1 - _expConst));
current.Adm_neg = (current.Dm_neg * _expConst) + (indicatorMemory.Adm_neg * (1 - _expConst)); ;
}
}
/// <summary>
/// 3. Get the true range of the price.
/// </summary>
private void GetAverageTrueRange(ref ADXCacheItem current) {
decimal yesterdayClose = indicatorMemory.OHLC.Close;
decimal trueRange = System.Math.Max(Math.Abs(current.OHLC.High - current.OHLC.Low),
System.Math.Max(Math.Abs(current.OHLC.High - yesterdayClose),
Math.Abs(yesterdayClose - current.OHLC.Low)));
//Get the current true range:
if (indicatorMemory.Atr == 0) {
current.Atr = trueRange;
} else {
current.Atr = (trueRange * _expConst) + ((1 - _expConst) * indicatorMemory.Atr);
}
}
/// <summary>
/// 4. Get the Directional Movement Index
/// </summary>
private void GetADX(ref ADXCacheItem current) {
decimal dmi_plus = 0;
decimal dmi_neg = 0;
if (current.Atr > 0) {
dmi_plus = (current.Adm_plus / current.Atr) * 100;
dmi_neg = (current.Adm_neg / current.Atr) * 100;
}
if ((dmi_plus + dmi_neg) != 0) {
current.Dx = (Math.Abs(dmi_plus - dmi_neg) / (dmi_plus + dmi_neg)) * 100;
} else {
current.Dx = indicatorMemory.Dx;
}
//Save the results.
current.DmiPos = dmi_plus;
current.DmiNeg = dmi_neg;
current.Adx = current.Dx * _expConst + (1 - _expConst) * indicatorMemory.Adx;
}
/// <summary>
/// Provide a structure for caching the previous values of the ADX
/// </summary>
public class ADXCacheItem {
public Candle OHLC = new Candle();
public bool Set = false;
public decimal Atr = 0;
public decimal Dm_plus = 0;
public decimal Dm_neg = 0;
public decimal Adm_plus = 0;
public decimal Adm_neg = 0;
public decimal Dx = 0;
public decimal DmiPos = 0;
public decimal DmiNeg = 0;
public decimal Adx = 0;
}
/// <summary>
/// Simple online "super-tradebar" generator for making an OHLC from multiple bars.
/// </summary>
public class Candle {
public Candle() { }
public decimal Open = 0;
public decimal High = Decimal.MinValue;
public decimal Low = Decimal.MaxValue;
public decimal Close = 0;
public int Samples = 0;
public void Update(TradeBar bar) {
if (Open == 0) Open = bar.Open;
if (High < bar.High) High = bar.High;
if (Low > bar.Low) Low = bar.Low;
Close = bar.Close;
Samples++;
}
}
/// <summary>
/// Cap the queue length
/// </summary>
public class FixedLengthQueue<T> : ConcurrentQueue<T>
{
private readonly object syncObject = new object();
public int Size { get; private set; }
public FixedLengthQueue(int size)
{
Size = size;
}
public new void Enqueue(T obj)
{
base.Enqueue(obj);
lock (syncObject)
{
while (base.Count > Size)
{
T outObj;
base.TryDequeue(out outObj);
}
}
}
}
} // End ADX Indicator Class
} // End Namespace