Added ExponentialMovingAverageCrossover and moved all of the moving average stuff into it's own folder.
This commit is contained in:
@@ -11,6 +11,7 @@ using MarketData.MarketDataModel;
|
||||
using MarketData.Generator;
|
||||
using MarketData.Utils;
|
||||
using System.Drawing.Drawing2D;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
|
||||
namespace MarketData.CNNProcessing
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
using MarketData.MarketDataModel;
|
||||
// Filename: BollingerBandGenerator.cs
|
||||
// Author:Sean Kessler
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using MarketData.DataAccess;
|
||||
using MarketData.Generator.Indicators;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.Numerical;
|
||||
using MarketData.Utils;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using MarketData.CNNProcessing;
|
||||
using MarketData.DataAccess;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.Utils;
|
||||
using System;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using MarketData.Cache;
|
||||
using MarketData.DataAccess;
|
||||
using MarketData.Generator.Indicators;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
using MarketData.Helper;
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.Numerical;
|
||||
|
||||
@@ -18,6 +18,7 @@ using StopLimit=MarketData.Generator.Model.StopLimit;
|
||||
using StopLimits=MarketData.Generator.Model.StopLimits;
|
||||
using MarketData.Generator.ModelGenerators;
|
||||
using Axiom.Interpreter;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
|
||||
namespace MarketData.Generator.CMTrend
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
using MarketData.Cache;
|
||||
using MarketData.MarketDataModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MarketData.Generator.MovingAverage
|
||||
{
|
||||
public static class ExponentialMovingAverageCrossover
|
||||
{
|
||||
public static MovingAverageCrossovers GetMovingAverageCrossovers(String symbol, DateTime analysisDate,double threshholdPercentDecimal=.05, int fastCrossOverDays=9, int slowCrossoverDays=41)
|
||||
{
|
||||
Prices prices = GBPriceCache.GetInstance().GetPrices(symbol, analysisDate, slowCrossoverDays * 6);
|
||||
if(prices == null || 0==prices.Count)return new MovingAverageCrossovers();
|
||||
|
||||
return GetMovingAverageCrossovers(prices, threshholdPercentDecimal, fastCrossOverDays, slowCrossoverDays);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetMovingAverageCrossovers
|
||||
/// Prices will be in descending order with the most recent price at index[0] and the least recent price at index[count-1]
|
||||
/// </summary>
|
||||
/// <param name="prices"></param>
|
||||
/// <param name="fastCrossOverDays">The fast crossover. Tom Basso uses 9</param>
|
||||
/// <param name="slowCrossoverDays">The slow crosser. Tom Basso uses 41</param>
|
||||
/// <param name="threshholdPercent">The threshhold percent. 5% would be .05</param>
|
||||
/// <returns></returns>
|
||||
public static MovingAverageCrossovers GetMovingAverageCrossovers(Prices prices, double threshholdPercentDecimal=.05, int fastCrossOverDays=9, int slowCrossoverDays=41)
|
||||
{
|
||||
MovingAverageCrossovers movingAverageCrossovers = new MovingAverageCrossovers();
|
||||
|
||||
if(prices == null || 0==prices.Count || prices.Count<=slowCrossoverDays)return movingAverageCrossovers;
|
||||
if(fastCrossOverDays >= slowCrossoverDays)return movingAverageCrossovers;
|
||||
|
||||
DMAPrices fastDMAPrices = MovingAverageGenerator.GenerateExponentialMovingAverage(prices, fastCrossOverDays);
|
||||
DMAPrices slowDMAPrices = MovingAverageGenerator.GenerateExponentialMovingAverage(prices, slowCrossoverDays);
|
||||
|
||||
if(null == fastDMAPrices || 0 == fastDMAPrices.Count)return movingAverageCrossovers;
|
||||
if(null == slowDMAPrices || 0 == slowDMAPrices.Count)return movingAverageCrossovers;
|
||||
|
||||
FindCrossovers(fastDMAPrices, slowDMAPrices, movingAverageCrossovers, threshholdPercentDecimal);
|
||||
|
||||
// put the most recent item in the lowest index
|
||||
movingAverageCrossovers = new MovingAverageCrossovers((movingAverageCrossovers as List<MovingAverageCrossover>).Where(x => x.IsChangeInTrend==true).OrderByDescending(x => x.EventDate).ToList());
|
||||
return movingAverageCrossovers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the sorter term (faster) crossed the longer term (slower) moving average then a direction change is noted.
|
||||
/// If the change carried more than 5% in that direction then consider it a successful trend
|
||||
/// </summary>
|
||||
/// <param name="fastDMAPrices"></param>
|
||||
/// <param name="slowDMAPrices"></param>
|
||||
/// <param name="movingAverageCrossovers"></param>
|
||||
private static void FindCrossovers(DMAPrices fastDMAPrices, DMAPrices slowDMAPrices,MovingAverageCrossovers movingAverageCrossovers, double threshholdPercentDecimal)
|
||||
{
|
||||
double trendChangePercentThreshhold = threshholdPercentDecimal*100.00; // if a change in direction carries more than 5% then consider is a successful trend
|
||||
movingAverageCrossovers.Clear();
|
||||
DateTime startDate = slowDMAPrices[slowDMAPrices.Count-1].Date;
|
||||
MovingAverageCrossover movingAverageCrossover = default;
|
||||
|
||||
DMAPricesByDate fastDMAPricesByDate = fastDMAPrices.GetDMAPricesByDate();
|
||||
DMAPricesByDate slowDMAPricesByDate = slowDMAPrices.GetDMAPricesByDate();
|
||||
|
||||
List<DateTime> availableDates = new List<DateTime>(slowDMAPricesByDate.Keys);
|
||||
|
||||
availableDates.Sort((a, b) => DateTime.Compare(a,b)); // earliest date should be in the lowest index, most recent date should be in the highest 2024[0], 2025[1], 2026[2] for example
|
||||
|
||||
int currentDirection=0; // 1:fast DMA is above the slow, -1:fast DMA is below the slow, 0:slow DMA == fastDMA
|
||||
|
||||
DMAPrice prevSlowDMAPrice = default;
|
||||
DMAPrice prevFastDMAPrice = default;
|
||||
|
||||
for(int index=0;index<availableDates.Count;index++)
|
||||
{
|
||||
DateTime analysisDate = availableDates[index];
|
||||
DMAPrice slowDMAPrice = slowDMAPricesByDate[analysisDate];
|
||||
DMAPrice fastDMAPrice = fastDMAPricesByDate[analysisDate];
|
||||
|
||||
if(index == 0) // establish an initial orientation of the fast and slow moving averages. We need to create a new record to have a current trend
|
||||
{
|
||||
if(fastDMAPrice.AVGPrice > slowDMAPrice.AVGPrice)
|
||||
{
|
||||
movingAverageCrossover = new MovingAverageCrossover();
|
||||
movingAverageCrossover.EventDate = analysisDate;
|
||||
movingAverageCrossover.Symbol = slowDMAPrice.Symbol;
|
||||
movingAverageCrossover.CrossOverDirection = MovingAverageCrossover.CrossoverDirectionEnum.UpStart;
|
||||
movingAverageCrossover.IsChangeInTrend = false;
|
||||
movingAverageCrossover.SlowDMAPrice = slowDMAPrice;
|
||||
movingAverageCrossover.FastDMAPrice = fastDMAPrice;
|
||||
movingAverageCrossover.ChangePercent=0.00;
|
||||
movingAverageCrossovers.Add(movingAverageCrossover);
|
||||
currentDirection = 1;
|
||||
}
|
||||
else if(fastDMAPrice.AVGPrice < slowDMAPrice.AVGPrice)
|
||||
{
|
||||
movingAverageCrossover = new MovingAverageCrossover();
|
||||
movingAverageCrossover.EventDate = analysisDate;
|
||||
movingAverageCrossover.Symbol = slowDMAPrice.Symbol;
|
||||
movingAverageCrossover.CrossOverDirection = MovingAverageCrossover.CrossoverDirectionEnum.DownStart;
|
||||
movingAverageCrossover.IsChangeInTrend = false;
|
||||
movingAverageCrossover.SlowDMAPrice = slowDMAPrice;
|
||||
movingAverageCrossover.FastDMAPrice = fastDMAPrice;
|
||||
movingAverageCrossover.ChangePercent=0.00;
|
||||
movingAverageCrossovers.Add(movingAverageCrossover);
|
||||
currentDirection = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
movingAverageCrossover = new MovingAverageCrossover();
|
||||
movingAverageCrossover.EventDate = analysisDate;
|
||||
movingAverageCrossover.Symbol = slowDMAPrice.Symbol;
|
||||
movingAverageCrossover.CrossOverDirection = MovingAverageCrossover.CrossoverDirectionEnum.NeutralStart;
|
||||
movingAverageCrossover.IsChangeInTrend = false;
|
||||
movingAverageCrossover.SlowDMAPrice = slowDMAPrice;
|
||||
movingAverageCrossover.FastDMAPrice = fastDMAPrice;
|
||||
movingAverageCrossover.ChangePercent=0.00;
|
||||
movingAverageCrossovers.Add(movingAverageCrossover);
|
||||
currentDirection = 0;
|
||||
}
|
||||
prevSlowDMAPrice = slowDMAPrice;
|
||||
prevFastDMAPrice = fastDMAPrice;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(fastDMAPrice.AVGPrice > slowDMAPrice.AVGPrice)
|
||||
{
|
||||
if(1 == currentDirection) // The fast is above the slow as it was previously
|
||||
{
|
||||
if(movingAverageCrossovers.Count>0) // check the last change record for a threshhold break
|
||||
{
|
||||
MovingAverageCrossover movingAverageCrossOver = movingAverageCrossovers[movingAverageCrossovers.Count-1];
|
||||
double changePercent = ((fastDMAPrice.AVGPrice - movingAverageCrossOver.FastDMAPrice.AVGPrice)/movingAverageCrossOver.FastDMAPrice.AVGPrice)*100.00;
|
||||
if(changePercent > 0.00 && changePercent > trendChangePercentThreshhold) // if the threshhold is exceeded then create a new record and mark it as a trend change
|
||||
{
|
||||
movingAverageCrossover = new MovingAverageCrossover();
|
||||
movingAverageCrossover.EventDate = analysisDate;
|
||||
movingAverageCrossover.Symbol = slowDMAPrice.Symbol;
|
||||
movingAverageCrossover.CrossOverDirection = MovingAverageCrossover.CrossoverDirectionEnum.UpCross;
|
||||
movingAverageCrossover.IsChangeInTrend = true;
|
||||
movingAverageCrossover.SlowDMAPrice = slowDMAPrice;
|
||||
movingAverageCrossover.FastDMAPrice = fastDMAPrice;
|
||||
movingAverageCrossover.ChangePercent=changePercent;
|
||||
movingAverageCrossovers.Add(movingAverageCrossover);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(-1 == currentDirection || 0 == currentDirection) // The fast is above the slow and it was below the slow previously
|
||||
{
|
||||
currentDirection = 1; // switch directions
|
||||
movingAverageCrossover = new MovingAverageCrossover();
|
||||
movingAverageCrossover.EventDate = analysisDate;
|
||||
movingAverageCrossover.Symbol = slowDMAPrice.Symbol;
|
||||
movingAverageCrossover.CrossOverDirection = MovingAverageCrossover.CrossoverDirectionEnum.UpCross;
|
||||
movingAverageCrossover.SlowDMAPrice = slowDMAPrice;
|
||||
movingAverageCrossover.FastDMAPrice = fastDMAPrice;
|
||||
double changePercent = Math.Abs(((fastDMAPrice.AVGPrice - slowDMAPrice.AVGPrice)/slowDMAPrice.AVGPrice)*100.00);
|
||||
movingAverageCrossover.ChangePercent=changePercent;
|
||||
if(changePercent>trendChangePercentThreshhold)movingAverageCrossover.IsChangeInTrend = true;
|
||||
else movingAverageCrossover.IsChangeInTrend = false;
|
||||
movingAverageCrossovers.Add(movingAverageCrossover);
|
||||
}
|
||||
}
|
||||
else if(fastDMAPrice.AVGPrice < slowDMAPrice.AVGPrice)
|
||||
{
|
||||
if(-1 == currentDirection) // The fast is below the slow as it was previously
|
||||
{
|
||||
if(movingAverageCrossovers.Count>0) // check the last change record for a threshhold break
|
||||
{
|
||||
movingAverageCrossover = movingAverageCrossovers[movingAverageCrossovers.Count-1];
|
||||
double changePercent = Math.Abs(((fastDMAPrice.AVGPrice - movingAverageCrossover.FastDMAPrice.AVGPrice)/movingAverageCrossover.FastDMAPrice.AVGPrice)*100.00);
|
||||
if(changePercent<0.00 && Math.Abs(changePercent)>trendChangePercentThreshhold) // if the threshhold is exceeded then create a new record and mark it as a trend change
|
||||
{
|
||||
movingAverageCrossover = new MovingAverageCrossover();
|
||||
movingAverageCrossover.EventDate = analysisDate;
|
||||
movingAverageCrossover.Symbol = slowDMAPrice.Symbol;
|
||||
movingAverageCrossover.CrossOverDirection = MovingAverageCrossover.CrossoverDirectionEnum.UpCross;
|
||||
movingAverageCrossover.IsChangeInTrend = true;
|
||||
movingAverageCrossover.SlowDMAPrice = slowDMAPrice;
|
||||
movingAverageCrossover.FastDMAPrice = fastDMAPrice;
|
||||
movingAverageCrossover.ChangePercent = changePercent;
|
||||
movingAverageCrossovers.Add(movingAverageCrossover);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(1 == currentDirection || 0 == currentDirection) // The fast is below the slow but it was above the slow previously so we've crossed
|
||||
{
|
||||
currentDirection = -1; // switch directions
|
||||
movingAverageCrossover = new MovingAverageCrossover();
|
||||
movingAverageCrossover.EventDate = analysisDate;
|
||||
movingAverageCrossover.Symbol = slowDMAPrice.Symbol;
|
||||
movingAverageCrossover.CrossOverDirection = MovingAverageCrossover.CrossoverDirectionEnum.DownCross;
|
||||
movingAverageCrossover.SlowDMAPrice = slowDMAPrice;
|
||||
movingAverageCrossover.FastDMAPrice = fastDMAPrice;
|
||||
double changePercent = Math.Abs(((fastDMAPrice.AVGPrice - slowDMAPrice.AVGPrice)/slowDMAPrice.AVGPrice)*100.00);
|
||||
movingAverageCrossover.ChangePercent=changePercent;
|
||||
if(changePercent>trendChangePercentThreshhold)movingAverageCrossover.IsChangeInTrend = true;
|
||||
else movingAverageCrossover.IsChangeInTrend = false;
|
||||
movingAverageCrossovers.Add(movingAverageCrossover);
|
||||
}
|
||||
}
|
||||
else // The fast and the slow are equal. There's nothing to do here
|
||||
{
|
||||
|
||||
}
|
||||
prevSlowDMAPrice = slowDMAPrice;
|
||||
prevFastDMAPrice = fastDMAPrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MarketData.Generator.MovingAverage
|
||||
{
|
||||
public class MovingAverageCrossovers : List<MovingAverageCrossover>
|
||||
{
|
||||
public MovingAverageCrossovers()
|
||||
{
|
||||
}
|
||||
|
||||
public MovingAverageCrossovers(List<MovingAverageCrossover> movingAverageCrossovers)
|
||||
{
|
||||
foreach(MovingAverageCrossover movingAverageCrossover in movingAverageCrossovers)
|
||||
{
|
||||
Add(movingAverageCrossover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MovingAverageCrossover
|
||||
{
|
||||
public enum CrossoverDirectionEnum{UpCross, DownCross, UpStart, DownStart, NeutralStart};
|
||||
public String Symbol { get; set; }
|
||||
public DateTime EventDate { get; set; }
|
||||
public CrossoverDirectionEnum CrossOverDirection {get; set;}
|
||||
public bool IsChangeInTrend { get; set; }
|
||||
public double ChangePercent { get; set; }
|
||||
public DMAPrice SlowDMAPrice { get; set; } // the slow DMA price associated with this crossover
|
||||
public DMAPrice FastDMAPrice { get; set; } // the fast DMA price associated with this crossover
|
||||
public double CurrentPrice {get{return SlowDMAPrice.CurrentPrice;}} // it doesn't matter if sourced from slow or fast since they both refer to the same underlying price
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("Symbol:").Append(Symbol);
|
||||
sb.Append(" Date:").Append(EventDate.ToShortDateString());
|
||||
sb.Append(" Direction:").Append(CrossOverDirection.ToString());
|
||||
sb.Append(" IsChangeInTrend:").Append(IsChangeInTrend.ToString());
|
||||
sb.Append(" ChangePercent:").Append(Utility.FormatNumber(ChangePercent,2));
|
||||
sb.Append(" ClosePrice:").Append(Utility.FormatCurrency(CurrentPrice));
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.DataAccess;
|
||||
using MarketData.Numerical;
|
||||
using MarketData.Utils;
|
||||
|
||||
namespace MarketData.Generator
|
||||
namespace MarketData.Generator.MovingAverage
|
||||
{
|
||||
public class MovingAverageGenerator
|
||||
{
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
using MarketData.MarketDataModel;
|
||||
|
||||
// Filename: StochasticsGenerator.cs
|
||||
|
||||
@@ -6,6 +6,7 @@ using MarketData.DataAccess;
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.Generator;
|
||||
using MarketData.Utils;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
|
||||
namespace MarketData.Helper
|
||||
{
|
||||
|
||||
@@ -162,6 +162,9 @@
|
||||
<Compile Include="Generator\Momentum\MGSessionParams.cs" />
|
||||
<Compile Include="Generator\Momentum\QualityIndicator.cs" />
|
||||
<Compile Include="Generator\Momentum\ScoreIndicator.cs" />
|
||||
<Compile Include="Generator\MovingAverage\ExponentialMovingAverageCrossover.cs" />
|
||||
<Compile Include="Generator\MovingAverage\MovingAverageCrossover.cs" />
|
||||
<Compile Include="Generator\MovingAverage\MovingAverageGenerator.cs" />
|
||||
<Compile Include="Generator\ParityGenerator.cs" />
|
||||
<Compile Include="Generator\DCFGenerator.cs" />
|
||||
<Compile Include="Generator\GainLoss\GainLossGenerator.cs" />
|
||||
@@ -300,7 +303,6 @@
|
||||
<Compile Include="MarketDataModel\Valuations.cs" />
|
||||
<Compile Include="MarketDataModel\YieldCurve.cs" />
|
||||
<Compile Include="MDTrace.cs" />
|
||||
<Compile Include="Generator\MovingAverageGenerator.cs" />
|
||||
<Compile Include="Helper\MovingAverageHelperSheet.cs" />
|
||||
<Compile Include="MarketDataModel\MovingDeviation.cs" />
|
||||
<Compile Include="Numerics\BlackScholes.cs" />
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Text;
|
||||
using System.Linq;
|
||||
using MarketData.Generator;
|
||||
using MarketData.Utils;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
|
||||
namespace MarketData.MarketDataModel
|
||||
{
|
||||
|
||||
18
Program.cs
18
Program.cs
@@ -23,6 +23,8 @@ using MarketData.Generator.CMTrend;
|
||||
using Axiom.Interpreter;
|
||||
using System.Data;
|
||||
using MarketData.CNNProcessing;
|
||||
using MySql.Data.MySqlClient;
|
||||
using MarketData.Generator.MovingAverage;
|
||||
|
||||
namespace MarketData
|
||||
{
|
||||
@@ -769,13 +771,19 @@ namespace MarketData
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(strLogFile));
|
||||
DateTime currentDate=DateTime.Now;
|
||||
|
||||
// Price price = MarketDataHelper.GetLatestPriceYahoo("^GSPC");
|
||||
Prices prices = new Prices();
|
||||
prices.Add(new Price(){Date=DateTime.Parse("1/28/2025"),Open=10,High=10,Low=10,Close=10});
|
||||
prices.Add(new Price(){Date=DateTime.Parse("1/29/2025"),Open=15,High=15,Low=15,Close=15});
|
||||
prices.Add(new Price(){Date=DateTime.Parse("1/30/2025"),Open=5,High=5,Low=5,Close=5});
|
||||
prices.Add(new Price(){Date=DateTime.Parse("1/31/2025"),Open=20,High=20,Low=20,Close=20});
|
||||
prices.Add(new Price(){Date=DateTime.Parse("2/1/2025"),Open=10,High=10,Low=10,Close=10});
|
||||
prices.Add(new Price(){Date=DateTime.Parse("2/2/2025"),Open=25,High=25,Low=25,Close=25});
|
||||
prices.Add(new Price(){Date=DateTime.Parse("2/3/2025"),Open=30,High=30,Low=30,Close=30});
|
||||
|
||||
DMAPrices dmaPrices = MovingAverageGenerator.GenerateMovingAverage(prices, 2);
|
||||
DMAPrices emaPrices = MovingAverageGenerator.GenerateExponentialMovingAverage(prices, 2);
|
||||
|
||||
// GetObservations(90,30);
|
||||
// CompressObservations("Observations.txt");
|
||||
|
||||
// Console.WriteLine(CNNClient.Model.inception.ToString());
|
||||
// CNNClient.Model model = (CNNClient.Model)Enum.Parse(typeof(CNNClient.Model),"inception",true);
|
||||
|
||||
DateTime maxHolidayDate =HolidayDA.GetMaxHolidayDate();
|
||||
if(currentDate>maxHolidayDate)
|
||||
|
||||
Reference in New Issue
Block a user