diff --git a/App.config b/App.config
index fa28871..9f87935 100644
--- a/App.config
+++ b/App.config
@@ -19,6 +19,6 @@
-
+
diff --git a/MGSHMomentumHelper.cs b/MGSHMomentumHelper.cs
new file mode 100644
index 0000000..2227278
--- /dev/null
+++ b/MGSHMomentumHelper.cs
@@ -0,0 +1,127 @@
+using MarketData.Generator.MGSHMomentum;
+using System;
+using System.Collections.Generic;
+
+namespace MarketData
+{
+ public static class MGSHMomentumHelper
+ {
+ public static void HandleMGSHSession(String[] args)
+ {
+ CommandArgs commandArgs = new CommandArgs(args);
+ if(!commandArgs.Has("SESSIONFILE"))
+ {
+ MDTrace.WriteLine(LogLevel.DEBUG,"Missing SESSIONFILE");
+ return;
+ }
+ MGSHMomentumBacktest momentumBacktest = new MGSHMomentumBacktest();
+ momentumBacktest.DisplaySession(commandArgs.Coalesce("SESSIONFILE"));
+ }
+
+ public static void HandleMGSHRunDaily(String[] args)
+ {
+ CommandArgs commandArgs = new CommandArgs(args);
+ if(!commandArgs.Has("SESSIONFILE,TRADEDATE"))
+ {
+ MDTrace.WriteLine(LogLevel.DEBUG,"SESSIONFILE and TRADEDATE are required parameters.");
+ return;
+ }
+ DateTime tradeDate = commandArgs.Get("TRADEDATE");
+ String pathSessionFile = commandArgs.Get("PATHSESSIONFILE");
+ MGSHMomentumBacktest momentumBacktest = new MGSHMomentumBacktest();
+ MGSHBacktestResult backtestResult = momentumBacktest.UpdateDaily(tradeDate, tradeDate, pathSessionFile);
+ backtestResult.Display();
+ }
+
+ public static void HandleMGSHRunBacktest(String[] args)
+ {
+ CommandArgs commandArgs = new CommandArgs(args);
+ MGSHConfiguration mgParams=new MGSHConfiguration();
+ if (!commandArgs.Has("STARTDATE,MAXPOSITIONS,INITIALCASH,HOLDINGPERIOD"))
+ {
+ if (!commandArgs.Has("STARTDATE")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing STARTDATE");
+ if (!commandArgs.Has("MAXPOSITIONS")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing MAXPOSITIONS");
+ if (!commandArgs.Has("INITIALCASH")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing INITIALCASH");
+ if (!commandArgs.Has("HOLDINGPERIOD")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing HOLDINGPERIOD");
+ return;
+ }
+ mgParams.MaxPositions=commandArgs.Coalesce("MAXPOSITIONS");
+ mgParams.InitialCash=commandArgs.Coalesce("INITIALCASH");
+ mgParams.HoldingPeriod=commandArgs.Coalesce("HOLDINGPERIOD");
+
+ if(commandArgs.Has("INCLUDETRADEMASTERFORSYMBOLSHELD"))
+ {
+ mgParams.IncludeTradeMasterForSymbolsHeld=commandArgs.Get("INCLUDETRADEMASTERFORSYMBOLSHELD");
+ }
+
+ if(commandArgs.Has("USESTOCHASTICS"))
+ {
+ mgParams.UseStochastics=commandArgs.Coalesce("USESTOCHASTICS",true);
+ }
+
+ if(commandArgs.Has("USESTOPLIMITS"))
+ {
+ mgParams.UseStopLimits=commandArgs.Coalesce("USESTOPLIMITS",false);
+ }
+
+ if(commandArgs.Has("STOPLIMITRISKPERCENTDECIMAL"))
+ {
+ mgParams.StopLimitRiskPercentDecimal=commandArgs.Coalesce("STOPLIMITRISKPERCENTDECIMAL",.12);
+ }
+
+ if(commandArgs.Has("USEHEDGING"))
+ {
+ mgParams.UseHedging=commandArgs.Coalesce("USEHEDGING",false);
+ if(commandArgs.Has("INITIALHEDGECASH"))
+ {
+ mgParams.HedgeInitialCash=commandArgs.Get("INITIALHEDGECASH");
+ }
+ }
+
+ if(commandArgs.Has("KEEPSLOTPOSITIONS"))
+ {
+ mgParams.KeepSlotPositions=commandArgs.Get("KEEPSLOTPOSITIONS");
+ }
+
+// ** M A C D
+ if(commandArgs.Has("USEMACD"))
+ {
+ mgParams.UseMACD=commandArgs.Coalesce("USEMACD",true);
+ }
+ if(commandArgs.Has("MACDREJECTSTRONGSELLSIGNALS"))
+ {
+ mgParams.MACDRejectStrongSellSignals=commandArgs.Coalesce("MACDREJECTSTRONGSELLSIGNALS",true);
+ }
+ if(commandArgs.Has("MACDREJECTWEAKSELLSIGNALS"))
+ {
+ mgParams.MACDRejectWeakSellSignals=commandArgs.Coalesce("MACDREJECTWEAKSELLSIGNALS",true);
+ }
+ if(commandArgs.Has("MACDSIGNALDAYS"))
+ {
+ mgParams.MACDSignalDays=commandArgs.Coalesce("MACDSIGNALDAYS",mgParams.MACDSignalDays);
+ }
+ if(commandArgs.Has("MACDSETUP"))
+ {
+ mgParams.MACDSetup=commandArgs.Coalesce("MACDSETUP",mgParams.MACDSetup);
+ }
+// **
+ MGSHQualityIndicator qualityIndicator=new MGSHQualityIndicator(MGSHQualityIndicator.QualityType.IDIndicator);
+ if(commandArgs.Has("QUALITYINDICATORTYPE")) qualityIndicator.Quality=MGSHQualityIndicator.ToQuality(commandArgs.Coalesce("QUALITYINDICATORTYPE","IDINDICATOR"));
+ mgParams.QualityIndicatorType=qualityIndicator.ToString();
+
+ mgParams.UseLowSlopeBetaCheck=true;
+ if(commandArgs.Has("USELOWSLOPEBETACHECK")) mgParams.UseLowSlopeBetaCheck=commandArgs.Coalesce("USELOWSLOPEBETACHECK",true);
+
+ DateTime startDate = commandArgs.Coalesce("STARTDATE");
+ DateTime endDate=commandArgs.Coalesce("ENDDATE",new DateTime());
+
+ String pathSessionFileName = commandArgs.Coalesce("SESSIONFILE", null);
+ if(null!=pathSessionFileName)pathSessionFileName=pathSessionFileName.Trim();
+
+ mgParams.DisplayHeader();
+ List results=new List();
+ MGSHMomentumBacktest backtestMomentum=new MGSHMomentumBacktest();
+ results.Add(backtestMomentum.PerformBacktest(startDate,endDate,pathSessionFileName,mgParams));
+ }
+ }
+}
diff --git a/MarketData.csproj b/MarketData.csproj
index 7d288d8..c903eab 100644
--- a/MarketData.csproj
+++ b/MarketData.csproj
@@ -72,6 +72,7 @@
+
diff --git a/Program.cs b/Program.cs
index 5fbd5a9..eb6beb3 100644
--- a/Program.cs
+++ b/Program.cs
@@ -25,6 +25,7 @@ using System.Data;
using MarketData.CNNProcessing;
using MySql.Data.MySqlClient;
using MarketData.Generator.MovingAverage;
+using MarketData.Generator.MGSHMomentum;
namespace MarketData
{
@@ -190,6 +191,10 @@ namespace MarketData
MDTrace.WriteLine(LogLevel.DEBUG," MGCLOSEPOSITION /SESSIONFILE: /SYMBOL: /PURCHASEDATE: /SELLPRICE: /SELLDATE: sells the specified position in the session file with either the supplied sell date and sell price.");
MDTrace.WriteLine(LogLevel.DEBUG," MGUPDATEPRICE /SYMBOL: /TRADEDATE: /PRICE: /SESSIONFILE:");
MDTrace.WriteLine(LogLevel.DEBUG," RUNBACKTEST /STARTDATE: /MAXPOSITIONS: /INITIALCASH: /HOLDINGPERIOD: /{ENDDATE}: /SESSIONFILE:");
+ MDTrace.WriteLine(LogLevel.DEBUG,"********** M G S H M O M E N T U M *********");
+ MDTrace.WriteLine(LogLevel.DEBUG," MGSHSESSION /SESSIONFILE:");
+ MDTrace.WriteLine(LogLevel.DEBUG," MGSHRUNBACKTEST /USEHEDGING: /HEDGEINITIALCASH: /USESTOPLIMITS: /KEEPSLOTPOSITIONS: /STARTDATE: /MAXPOSITIONS: /INITIALCASH: /HOLDINGPERIOD: /{ENDDATE}: /SESSIONFILE: ");
+ MDTrace.WriteLine(LogLevel.DEBUG," MGSHRUNDAILY /SESSIONFILE: /TRADEDATE:");
MDTrace.WriteLine(LogLevel.DEBUG, "*********** C L E N O W M O M E N T U M (C M M O M E N T U M )************");
MDTrace.WriteLine(LogLevel.DEBUG, " RUNCMBACKTEST /STARTDATE: /MAXPOSITIONS: /INITIALCASH: /HOLDINGPERIOD: /{USEBINBASEDPOSITIONSIZING}: /{USEBINBASEDPOSITIONSIZINGNUMBINS}: /{TARGETBETA}: /{ENDDATE}: /SESSIONFILE: /{USECNN}: /{USECNNHOST}: /{USECNNDAYCOUNT}:");
MDTrace.WriteLine(LogLevel.DEBUG, " CMSESSION /SESSIONFILE:");
@@ -758,6 +763,212 @@ namespace MarketData
outStream.Close();
outStream.Dispose();
}
+// *****************************************************************************************************************************************************
+
+ public static void HedgeTest()
+ {
+ String hedgeShortSymbol="SH";
+ double initialRiskPercentDecimal=.12;
+ double cash=10000;
+ double cashToInvest=3000;
+ double totalGainLoss=0.00;
+ bool hedgeOn=false;
+ int totalWinners=0;
+ int totalLosers=0;
+ int hedgeStopLimitScalingVolatilityDays=14;
+ int hedgeMinDaysBetweenStopAdjustments=1;
+
+ MGSHPosition position = default;
+
+
+ MDTrace.WriteLine(LogLevel.DEBUG,"START");
+ DateTime analysisStartDate=DateTime.Parse("01/31/2018");
+// DateTime analysisStartDate=DateTime.Parse("01/01/2011");
+// DateTime analysisStartDate=DateTime.Parse("06/06/2018");
+ DateTime analysisEndDate=DateTime.Parse("12/31/2024");
+ Prices prices = PricingDA.GetPrices(hedgeShortSymbol);
+
+ prices=new Prices(prices.Where(x => x.Date > analysisStartDate).ToList());
+
+ BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices);
+ BollingerBandElementsByDate bollingerBandElementsByDate = bollingerBands.GetBollingerBandElementsByDate();
+
+ PricesByDate pricesByDate = prices.GetPricesByDate();
+ List dates = new List(pricesByDate.Keys);
+
+ MGSHPositions AllPositions = new MGSHPositions();
+ MarketData.Generator.Model.StopLimits StopLimits = new MarketData.Generator.Model.StopLimits();
+
+ HedgeManager hedgeManager = new HedgeManager(){Verbose=true};
+
+ for(int dateIndex=dates.Count-1;dateIndex>=0;dateIndex--)
+ {
+ DateTime analysisDate = dates[dateIndex];
+ if(analysisDate > analysisEndDate)break;
+ if(!bollingerBandElementsByDate.ContainsKey(analysisDate))continue;
+ BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[analysisDate];
+
+ if(!hedgeOn && hedgeManager.IsOpenHedgeIndicator(analysisDate))
+ {
+ hedgeOn=true;
+ position = new MGSHPosition();
+ position.Symbol=hedgeShortSymbol;
+ position.PurchasePrice = bollingerBandElement.Close;
+ position.PurchaseDate = analysisDate;
+ position.SellDate=Utility.Epoch;
+ position.InitialStopLimit=position.PurchasePrice/(1.00+initialRiskPercentDecimal);
+ position.TrailingStopLimit=position.InitialStopLimit;
+ position.LastStopAdjustment=Utility.Epoch;
+ position.R=initialRiskPercentDecimal;
+ double cashAllocation = Math.Min(cash, cashToInvest);
+ position.Shares=(int)(cashAllocation/bollingerBandElement.Close);
+ cash-=position.Shares*bollingerBandElement.Close;
+
+// This is for the simulation so that I can see the initial position as a stop limit in the UI
+ MarketData.Generator.Model.StopLimit stopLimit = new MarketData.Generator.Model.StopLimit()
+ {
+ Symbol=hedgeShortSymbol,
+ AnalysisDate=analysisDate,
+ PreviousStop=position.PurchasePrice,
+ NewStop=position.TrailingStopLimit,
+ CurrentPriceLow=0.00,
+ CurrentPriceClose=0.00,
+ PriceTrendIndicatorSlope=0.00
+ };
+ StopLimits.Add(stopLimit);
+
+ MDTrace.WriteLine(LogLevel.DEBUG,$"Hedge BUY {analysisDate.ToShortDateString()} {Utility.FormatNumber(position.Shares,2)} shares @ {Utility.FormatCurrency(bollingerBandElement.Close)} Exposure:{Utility.FormatCurrency(position.Shares*bollingerBandElement.Close)}");
+ }
+ else if(hedgeOn) // This will check for stop loss violation and close the position
+ {
+ Price price = GBPriceCache.GetInstance().GetPrice(hedgeShortSymbol, analysisDate);
+ if(null == price)
+ {
+ MDTrace.WriteLine(LogLevel.DEBUG,$"No price for {hedgeShortSymbol} on {analysisDate.ToShortDateString()}");
+ continue;
+ }
+ if(price.Close0)totalWinners++;
+ else totalLosers++;
+ totalGainLoss+=position.GainLoss;
+ cash+=position.MarketValue;
+ MDTrace.WriteLine(LogLevel.DEBUG,$"Hedge SELL {analysisDate.ToShortDateString()} {Utility.FormatNumber(position.Shares,2)} shares @ {Utility.FormatCurrency(position.CurrentPrice)} Gain/Loss:{Utility.FormatCurrency(position.GainLoss)} Gain/Loss(%):{Utility.FormatPercent(position.GainLossPcnt,2)}");
+ MDTrace.WriteLine(LogLevel.DEBUG,"**************************************************");
+ AllPositions.Add(position);
+
+ MarketData.Generator.Model.StopLimit stopLimit = new MarketData.Generator.Model.StopLimit()
+ {
+ Symbol=hedgeShortSymbol,
+ AnalysisDate=analysisDate,
+ PreviousStop=position.PurchasePrice,
+ NewStop=position.CurrentPrice,
+ CurrentPriceLow=0.00,
+ CurrentPriceClose=0.00,
+ PriceTrendIndicatorSlope=0.00
+ };
+ StopLimits.Add(stopLimit);
+ }
+ else if(hedgeManager.IsLowerBandBreakIndicator(analysisDate, position))
+ {
+ MarketData.Generator.Model.StopLimit stopLimit = hedgeManager.EvaluateStopPriceHedge(analysisDate, position, hedgeStopLimitScalingVolatilityDays, hedgeMinDaysBetweenStopAdjustments);
+ if(null != stopLimit)StopLimits.Add(stopLimit);
+ }
+ }
+ }
+ MGSHSessionParams sessionParams = new MGSHSessionParams();
+ sessionParams.LastUpdated=DateTime.Now;
+ sessionParams.TradeDate=DateTime.Now;
+ sessionParams.StartDate=DateTime.Now;
+ sessionParams.AnalysisDate=DateTime.Now;
+ sessionParams.Configuration=new MGSHConfiguration();
+ sessionParams.ActivePositions=new MGSHActivePositions();
+ sessionParams.AllPositions=AllPositions;
+ sessionParams.CashBalance=cash;
+ sessionParams.NonTradeableCash=0.00;
+ sessionParams.StopLimits=StopLimits;
+ sessionParams.HedgePositions= new MGSHPositions();
+ sessionParams.Cycle = 0;
+
+ MGSHSessionManager mgSession = new MGSHSessionManager();
+ mgSession.SaveSession(sessionParams,"MGSH_PROTO_20250128_2.TXT");
+ MDTrace.WriteLine(LogLevel.DEBUG,String.Format($"Total Gain/Loss:{Utility.FormatCurrency(totalGainLoss)}"));
+ MDTrace.WriteLine(LogLevel.DEBUG,String.Format($"Cash:{Utility.FormatCurrency(cash)}"));
+ MDTrace.WriteLine(LogLevel.DEBUG,String.Format($"Open:{hedgeOn}"));
+
+ return;
+ }
+// ****************************************************************************************************************************************************************
+ public static void CrossoverExample()
+ {
+ // Crossover examples.
+ // Example 1
+ //List symbols = PricingDA.GetSymbols();
+ //List crossovers = new MovingAverageCrossovers();
+ //DateTime analysisDate = DateTime.Parse("12/31/2024");
+ //for (int index = 0; index < symbols.Count; index++)
+ //{
+ // if (0 == (index % 500)) Console.WriteLine($"Working on {index}");
+ // String symbol = symbols[index];
+ // Prices prices = GBPriceCache.GetInstance().GetPrices(symbol, analysisDate, 252);
+ // MovingAverageCrossovers movingAverageCrossovers = ExponentialMovingAverageCrossover.GetMovingAverageCrossovers(prices, .05); // 5%
+ // movingAverageCrossovers = new MovingAverageCrossovers(movingAverageCrossovers.Where(x => x.EventDate.Equals(analysisDate)).ToList());
+ // crossovers.AddRange(movingAverageCrossovers);
+ //}
+ //foreach (MovingAverageCrossover movingAverageCrossover in crossovers)
+ //{
+ // Console.WriteLine(movingAverageCrossover.ToString());
+ //}
+
+ // Example 2
+ //String symbol = "SH";
+ //DateTime analysisDate = DateTime.Parse("12/31/2024");
+ //Prices prices = GBPriceCache.GetInstance().GetPrices(symbol, analysisDate, 252);
+ //MovingAverageCrossovers movingAverageCrossovers = ExponentialMovingAverageCrossover.GetMovingAverageCrossovers(prices, .025);
+ //foreach (MovingAverageCrossover movingAverageCrossover in movingAverageCrossovers)
+ //{
+ // Console.WriteLine(movingAverageCrossover.ToString());
+ //}
+
+ //DMAPrices fastDMAPrices = MovingAverageGenerator.GenerateExponentialMovingAverage(prices, 9);
+ //DMAPrices slowDMAPrices=MovingAverageGenerator.GenerateExponentialMovingAverage(prices, 41);
+ //DMAPricesByDate fastDMAPricesByDate=fastDMAPrices.GetDMAPricesByDate();
+ //DMAPricesByDate slowDMAPricesByDate=slowDMAPrices.GetDMAPricesByDate();
+ //List availableDates = new List(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
+ //StreamWriter streamWriter = new StreamWriter(new FileStream("MovingAverage.csv",FileMode.Create));
+ //streamWriter.WriteLine("Date,Fast,Slow");
+ //foreach(DateTime date in availableDates)
+ //{
+ // DMAPrice fastDMAPrice = fastDMAPricesByDate[date];
+ // DMAPrice slowDMAPrice = slowDMAPricesByDate[date];
+ // streamWriter.WriteLine($"{date.ToShortDateString()},{fastDMAPrice.AVGPrice},{slowDMAPrice.AVGPrice}");
+ //}
+ //streamWriter.Flush();
+ //streamWriter.Close();
+ //streamWriter.Dispose();
+
+ // Example 3
+ //DateTime beginDate = DateTime.Parse("12/31/2018");
+ //DateTime stopDate = DateTime.Parse("12/31/2024");
+ //String symbol="^VIX";
+ //DateGenerator dateGenerator = new DateGenerator();
+ //while(beginDate<=stopDate)
+ //{
+ // Prices prices = GBPriceCache.GetInstance().GetPrices(symbol, beginDate, 252);
+ // MovingAverageCrossovers movingAverageCrossovers = ExponentialMovingAverageCrossover.GetMovingAverageCrossovers(prices, .025, 20, 50); // 1.75%
+ // if(null != movingAverageCrossovers && movingAverageCrossovers.Count>0 && movingAverageCrossovers[0].EventDate.Equals(beginDate))
+ // {
+ // MDTrace.WriteLine(LogLevel.DEBUG,$"Found a crossover {movingAverageCrossovers[0].ToString()}");
+ // }
+ // beginDate = dateGenerator.FindNextBusinessDay(beginDate);
+ //}
+ }
+
@@ -771,19 +982,40 @@ namespace MarketData
Trace.Listeners.Add(new TextWriterTraceListener(strLogFile));
DateTime currentDate=DateTime.Now;
- 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);
+// CompanyProfile c1 = MarketDataHelper.GetCompanyProfile("AAME");
+ CompanyProfiles companyProfiles = CompanyProfileDA.GetCompanyProfiles();
+ List symbols = companyProfiles.Select(x => x.Symbol).ToList();
+ foreach(String symbol in symbols)
+ {
+ CompanyProfile companyProfile = MarketDataHelper.GetCompanyProfile(symbol);
+ if (null != companyProfile) {
+ MDTrace.WriteLine(LogLevel.DEBUG, $"Symbol:{symbol} Sector:{companyProfile.Sector} Industry:{companyProfile.Industry} Description:{companyProfile.Description}");
+ MDTrace.WriteLine(LogLevel.DEBUG, "");
+ }
+ Thread.Sleep(2000);
+ }
+
+
+
+
+// CompanyProfile companyProfile = MarketDataHelper.GetCompanyProfile("MOD");
+ //PortfolioTrades portfolioTrades = PortfolioDA.GetOpenTrades();
+ //List symbols = portfolioTrades.Select(x => x.Symbol).Distinct().ToList();
+ //for (int rindex=0; rindexmaxHolidayDate)
@@ -1461,7 +1693,22 @@ namespace MarketData
Program.HandleCMTSession(args);
}
// *************************************************************************************************************************************************************************************************************************
-// ************************************************************************************************** M G M O M E N T U M *************************************************************************************************
+// ************************************************************************************************** M G S H M O M E N T U M *************************************************************************************************
+// *************************************************************************************************************************************************************************************************************************
+ else if(arg.Equals("MGSHSESSION"))
+ {
+ MGSHMomentumHelper.HandleMGSHSession(args);
+ }
+ else if(arg.Equals("MGSHRUNBACKTEST"))
+ {
+ MGSHMomentumHelper.HandleMGSHRunBacktest(args);
+ }
+ else if(arg.Equals("MGSHRUNDAILY"))
+ {
+ MGSHMomentumHelper.HandleMGSHRunDaily(args);
+ }
+// *************************************************************************************************************************************************************************************************************************
+// ************************************************************************************************** M G M O M E N T U M *************************************************************************************************
// *************************************************************************************************************************************************************************************************************************
else if (arg.Equals("RUNMOMENTUM"))
{
@@ -2011,7 +2258,7 @@ namespace MarketData
ThreadPool.QueueUserWorkItem(delegate
{
- UpdateAnalystPriceTarget(); // finance.yahoo.com
+ UpdateAnalystPriceTarget(); // MarketBeat
GetETFHoldings(); // finance.yahoo.com
resetEvents[STAGE_9].Set();
});