Compare commits
1 Commits
MKDT_0002
...
MKDT_CNN01
| Author | SHA1 | Date | |
|---|---|---|---|
| 22b387a2e3 |
@@ -7,7 +7,7 @@ namespace MarketData.CNNProcessing
|
|||||||
{
|
{
|
||||||
public class CNNClient
|
public class CNNClient
|
||||||
{
|
{
|
||||||
public enum Model{resnet50,resnet50B,resnet50_20241024_270,inception,vgg16,lenet5,ping};
|
public enum Model{resnet50,resnet50B,resnet50_20241024_270,inception,vgg16,lenet5,convnext,ping};
|
||||||
private static readonly string Alive="Alive";
|
private static readonly string Alive="Alive";
|
||||||
private readonly HttpClient client = new HttpClient();
|
private readonly HttpClient client = new HttpClient();
|
||||||
private string baseUrl;
|
private string baseUrl;
|
||||||
|
|||||||
@@ -3,27 +3,75 @@ using System.IO;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MarketData.Utils;
|
using MarketData.Utils;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace MarketData.CNNProcessing
|
namespace MarketData.CNNProcessing
|
||||||
{
|
{
|
||||||
public class CNNProcessor
|
public class CNNProcessor
|
||||||
{
|
{
|
||||||
private static int dayCount=270;
|
private static int dayCount=270; // This is the default days
|
||||||
private static int width=128;
|
private static int width=128; // This is the default width
|
||||||
private static int height=128;
|
private static int height=128; // THis is the defaukt height
|
||||||
|
|
||||||
private CNNProcessor()
|
private CNNProcessor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GenerateTraining()
|
/// <summary>
|
||||||
|
/// GenerateTraining - This is the new one. Please refer to the CNNImageProcessor project for information on how to call this method.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="avoid">This is the collection of avoid holdings</param>
|
||||||
|
/// <param name="good">This is the collection of good holdings</param>
|
||||||
|
/// <param name="dimension">The image dimensions. for example 224 for 224x224 or 128 for 128x128</param>
|
||||||
|
/// <param name="histDays">This is the number of histDays. For example I used 90 for convnext</param>
|
||||||
|
/// <param name="generateType">The type. For example I used BollingerBandWithVIX which is a bollinger band with ^VIX overay for convnext</param>
|
||||||
|
/// <param name="rootFolder"></param>
|
||||||
|
public static void GenerateTraining(List<Holding> avoid, List<Holding> good, int dimension, int histDays,TestCase.GenerateType generateType=TestCase.GenerateType.BollingerBandWithVIX,String rootFolder=@"C:\boneyard\DeepLearning\ModelInputData\")
|
||||||
|
{
|
||||||
|
TestCases testCases=new TestCases();
|
||||||
|
DataProcessor dataProcessor=new DataProcessor();
|
||||||
|
dataProcessor.Width=dimension;
|
||||||
|
dataProcessor.Height=dimension;
|
||||||
|
dataProcessor.PenWidthArray=new float[]{.75f,1.00f,1.12f};
|
||||||
|
|
||||||
|
if(!rootFolder.EndsWith(@"\"))rootFolder+=@"\";
|
||||||
|
// [0] Data - The avoid data
|
||||||
|
foreach(Holding holding in avoid)
|
||||||
|
{
|
||||||
|
testCases.Add(new TestCase(holding.Symbol,holding.PurchaseDate,histDays,TestCase.CaseType.Training,generateType));
|
||||||
|
}
|
||||||
|
dataProcessor.SetOutputFolderPath(rootFolder+"0");
|
||||||
|
dataProcessor.ClearFolderPath();
|
||||||
|
dataProcessor.ProcessData(testCases);
|
||||||
|
testCases.Clear();
|
||||||
|
|
||||||
|
// [1] Data - The good data
|
||||||
|
foreach(Holding holding in good)
|
||||||
|
{
|
||||||
|
testCases.Add(new TestCase(holding.Symbol,holding.PurchaseDate,histDays,TestCase.CaseType.Training,generateType));
|
||||||
|
}
|
||||||
|
dataProcessor.SetOutputFolderPath(rootFolder+"1");
|
||||||
|
dataProcessor.ClearFolderPath();
|
||||||
|
dataProcessor.ProcessData(testCases);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GenerateTraining - This is the old methof training the resnet model. Please see above
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rootFolder"></param>
|
||||||
|
public static void GenerateTraining(String rootFolder=@"C:\boneyard\DeepLearning\ModelInputData\")
|
||||||
{
|
{
|
||||||
TestCases testCases=new TestCases();
|
TestCases testCases=new TestCases();
|
||||||
DataProcessor dataProcessor=new DataProcessor();
|
DataProcessor dataProcessor=new DataProcessor();
|
||||||
dataProcessor.Width=width;
|
dataProcessor.Width=width;
|
||||||
dataProcessor.Height=height;
|
dataProcessor.Height=height;
|
||||||
dataProcessor.PenWidthArray=new float[]{.50f,.75f,1.00f,1.12f,1.25f,1.31f,1.37f,1.50f,1.56f,1.62f,1.75f,1.87f,2.00f};
|
// dataProcessor.PenWidthArray=new float[]{.50f,.75f,1.00f,1.12f,1.25f,1.31f,1.37f,1.50f,1.56f,1.62f,1.75f,1.87f,2.00f};
|
||||||
|
|
||||||
|
// Testing with 20,000 images in each set so reducing this use of pens to just one. It was producing 260,000 images for each classification,
|
||||||
|
// takings many hours to build the datasets
|
||||||
|
dataProcessor.PenWidthArray=new float[]{.75f,1.00f,1.12f};
|
||||||
|
|
||||||
|
if(!rootFolder.EndsWith(@"\"))rootFolder+=@"\";
|
||||||
// [0] Data - The avoid data
|
// [0] Data - The avoid data
|
||||||
testCases.Add(new TestCase("CENX",DateTime.Parse("03/31/2022"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
testCases.Add(new TestCase("CENX",DateTime.Parse("03/31/2022"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
||||||
testCases.Add(new TestCase("ICPT",DateTime.Parse("12/31/2019"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
testCases.Add(new TestCase("ICPT",DateTime.Parse("12/31/2019"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
||||||
@@ -56,8 +104,8 @@ namespace MarketData.CNNProcessing
|
|||||||
testCases.Add(new TestCase("INBX",DateTime.Parse("01/31/2024"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
testCases.Add(new TestCase("INBX",DateTime.Parse("01/31/2024"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
||||||
testCases.Add(new TestCase("WYNN",DateTime.Parse("02/28/2023"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
testCases.Add(new TestCase("WYNN",DateTime.Parse("02/28/2023"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
||||||
|
|
||||||
|
// ****
|
||||||
dataProcessor.SetOutputFolderPath(@"C:\boneyard\DeepLearning\ModelInputData\0");
|
dataProcessor.SetOutputFolderPath(rootFolder+"0");
|
||||||
dataProcessor.ProcessData(testCases);
|
dataProcessor.ProcessData(testCases);
|
||||||
testCases.Clear();
|
testCases.Clear();
|
||||||
|
|
||||||
@@ -102,7 +150,8 @@ namespace MarketData.CNNProcessing
|
|||||||
testCases.Add(new TestCase("DOCU",DateTime.Parse("05/30/2020"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
testCases.Add(new TestCase("DOCU",DateTime.Parse("05/30/2020"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
||||||
testCases.Add(new TestCase("SIG",DateTime.Parse("10/30/2020"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
testCases.Add(new TestCase("SIG",DateTime.Parse("10/30/2020"),270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));
|
||||||
|
|
||||||
dataProcessor.SetOutputFolderPath(@"C:\boneyard\DeepLearning\ModelInputData\1");
|
// ***
|
||||||
|
dataProcessor.SetOutputFolderPath(rootFolder+"1");
|
||||||
dataProcessor.ProcessData(testCases);
|
dataProcessor.ProcessData(testCases);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,4 +253,76 @@ namespace MarketData.CNNProcessing
|
|||||||
Console.WriteLine("");
|
Console.WriteLine("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Holding
|
||||||
|
{
|
||||||
|
public String Symbol {get;set;}
|
||||||
|
public DateTime PurchaseDate {get; set; }
|
||||||
|
public double PurchasePrice {get;set;}
|
||||||
|
public DateTime SellDate {get; set; }
|
||||||
|
public double SellPrice {get;set;}
|
||||||
|
public double GainLoss{ get; set;}
|
||||||
|
public double GainLossPercent {get;set;}
|
||||||
|
private static readonly string[] DateFormats = { "MM/dd/yyyy", "M/dd/yyyy", "M/d/yyyy" };
|
||||||
|
private static readonly CultureInfo UsCulture = CultureInfo.GetCultureInfo("en-US");
|
||||||
|
|
||||||
|
public static String Heading
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "Symbol,Shares,Purchase Date,Purchase Price,Sell Date,Sell Price,Exposure,Beta,BetaMonths,SharpeRatio,RiskAdjustedWeight,RiskAdjustedAllocation,TargetBetaOverBeta,Score,CNN Prediction,Market Value,Gain Loss,Gain Loss (%)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String ToTestCase()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.Append("testCases.Add(new TestCase(").Append("\"").Append(Symbol).Append("\"").Append(",");
|
||||||
|
sb.Append("DateTime.Parse(").Append("\"").Append(Utility.DateTimeToStringMMSDDSYYYY(PurchaseDate)).Append("\")").Append(",");
|
||||||
|
sb.Append("270,TestCase.CaseType.Training,TestCase.GenerateType.BollingerBand));");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override String ToString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.Append(Symbol).Append(",");
|
||||||
|
sb.Append(","); // shares
|
||||||
|
sb.Append(PurchaseDate.ToShortDateString()).Append(",");
|
||||||
|
sb.Append(Utility.FormatNumber(PurchasePrice,3)).Append(",");
|
||||||
|
sb.Append(SellDate.ToShortDateString()).Append(",");
|
||||||
|
sb.Append(Utility.FormatNumber(SellPrice,3)).Append(",");
|
||||||
|
sb.Append(","); //exposure
|
||||||
|
sb.Append(","); //beta
|
||||||
|
sb.Append(","); //bta months
|
||||||
|
sb.Append(","); //sharpe ratio
|
||||||
|
sb.Append(","); //risk adjusted weight
|
||||||
|
sb.Append(","); //RiskAdjustedAllocation
|
||||||
|
sb.Append(","); //TargetBetaOverBeta
|
||||||
|
sb.Append(","); //Score
|
||||||
|
sb.Append(","); //CNNPrediction
|
||||||
|
sb.Append(","); //Market Value
|
||||||
|
sb.Append(Utility.FormatNumber(GainLoss,3)).Append(",");
|
||||||
|
sb.Append(Utility.FormatNumber(GainLossPercent,3));
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Holding FromString(string strLine)
|
||||||
|
{
|
||||||
|
string[] items = strLine.Split(',');
|
||||||
|
|
||||||
|
Holding holding = new Holding();
|
||||||
|
holding.Symbol = items[0];
|
||||||
|
if(string.IsNullOrEmpty(holding.Symbol))return null;
|
||||||
|
holding.PurchaseDate = DateTime.ParseExact(items[2], DateFormats, UsCulture, DateTimeStyles.AssumeLocal);
|
||||||
|
holding.PurchasePrice = double.Parse(items[3], UsCulture);
|
||||||
|
holding.SellDate = DateTime.ParseExact(items[4], DateFormats, UsCulture, DateTimeStyles.AssumeLocal);
|
||||||
|
holding.SellPrice = double.Parse(items[5], UsCulture);
|
||||||
|
holding.GainLoss = double.Parse(items[16], UsCulture);
|
||||||
|
holding.GainLossPercent = double.Parse(items[17].TrimEnd('%'), UsCulture) / 100.0;
|
||||||
|
|
||||||
|
return holding;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace MarketData.CNNProcessing
|
|||||||
Height=height;
|
Height=height;
|
||||||
PenWidth=2f;
|
PenWidth=2f;
|
||||||
DrawingBrush=new SolidBrush(Color.Black);
|
DrawingBrush=new SolidBrush(Color.Black);
|
||||||
|
DrawingBrushRed=new SolidBrush(Color.Red);
|
||||||
FillBrush=new SolidBrush(Color.White);
|
FillBrush=new SolidBrush(Color.White);
|
||||||
DrawPrice=true;
|
DrawPrice=true;
|
||||||
UseGrayScale=false;
|
UseGrayScale=false;
|
||||||
@@ -59,6 +60,11 @@ namespace MarketData.CNNProcessing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
///<param name="value">Gets/Sets the drawing brush brush</param>
|
///<param name="value">Gets/Sets the drawing brush brush</param>
|
||||||
public Brush DrawingBrush{get;set;}
|
public Brush DrawingBrush{get;set;}
|
||||||
|
/// <summary>
|
||||||
|
/// DrawingBrush
|
||||||
|
/// </summary>
|
||||||
|
///<param name="value">Gets/Sets the drawing brush brush</param>
|
||||||
|
public Brush DrawingBrushRed{get;set;}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DrawBlack
|
/// DrawBlack
|
||||||
@@ -143,6 +149,29 @@ namespace MarketData.CNNProcessing
|
|||||||
this.strFolderPath=strFolderPath;
|
this.strFolderPath=strFolderPath;
|
||||||
if(!this.strFolderPath.EndsWith(@"\"))this.strFolderPath=this.strFolderPath+@"\";
|
if(!this.strFolderPath.EndsWith(@"\"))this.strFolderPath=this.strFolderPath+@"\";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ClearFolderPath
|
||||||
|
/// </summary>
|
||||||
|
///<param name="testCases">The test cases</param>
|
||||||
|
public void ClearFolderPath()
|
||||||
|
{
|
||||||
|
if(String.IsNullOrEmpty(strFolderPath))throw new InvalidDataException($"{nameof(strFolderPath)} cannot be null");
|
||||||
|
if(!Directory.Exists(strFolderPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(strFolderPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String[] pathFileNames = Directory.GetFiles(strFolderPath);
|
||||||
|
Console.WriteLine($"Deleting {pathFileNames.Length} files from {strFolderPath}");
|
||||||
|
foreach(String file in pathFileNames)
|
||||||
|
{
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void ProcessData(TestCases testCases)
|
public void ProcessData(TestCases testCases)
|
||||||
{
|
{
|
||||||
for(int index=0;index<testCases.Count;index++)
|
for(int index=0;index<testCases.Count;index++)
|
||||||
@@ -173,7 +202,7 @@ namespace MarketData.CNNProcessing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // Bollinger bands
|
else if(testCase.TypeGenerate.Equals(TestCase.GenerateType.BollingerBand))// Bollinger bands
|
||||||
{
|
{
|
||||||
if(null==MovingAverageArray)
|
if(null==MovingAverageArray)
|
||||||
{
|
{
|
||||||
@@ -194,7 +223,6 @@ namespace MarketData.CNNProcessing
|
|||||||
for(int avgIndex=0;avgIndex<MovingAverageArray.Length;avgIndex++)
|
for(int avgIndex=0;avgIndex<MovingAverageArray.Length;avgIndex++)
|
||||||
{
|
{
|
||||||
int movingAverage=MovingAverageArray[avgIndex];
|
int movingAverage=MovingAverageArray[avgIndex];
|
||||||
|
|
||||||
for(int penIndex=0;penIndex<PenWidthArray.Length;penIndex++)
|
for(int penIndex=0;penIndex<PenWidthArray.Length;penIndex++)
|
||||||
{
|
{
|
||||||
float penWidth=PenWidthArray[penIndex];
|
float penWidth=PenWidthArray[penIndex];
|
||||||
@@ -208,7 +236,22 @@ namespace MarketData.CNNProcessing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // Bollinger Bands
|
||||||
|
else if(testCase.TypeGenerate.Equals(TestCase.GenerateType.BollingerBandWithVIX))
|
||||||
|
{
|
||||||
|
for (int penIndex = 0; penIndex < PenWidthArray.Length; penIndex++)
|
||||||
|
{
|
||||||
|
float penWidth = PenWidthArray[penIndex];
|
||||||
|
for (int noiseIndex = 0; noiseIndex < NoiseArray.Length; noiseIndex++)
|
||||||
|
{
|
||||||
|
double noise = NoiseArray[noiseIndex];
|
||||||
|
String strPathFileName = CreateFileName(strFolderPath, testCase.Symbol, testCase.DayCount, index, penIndex, noiseIndex, testCase.TypeCase, testCase.TypeGenerate, testCase.PurchaseDate);
|
||||||
|
testCase.PathFileNames.Add(strPathFileName);
|
||||||
|
ProcessBollingerBandDataWithVolatility(testCase, penWidth, noise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // Bollinger Bands with ~VIX
|
||||||
|
else throw new InvalidDataException("Unknown option");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String CreateFileName(String strFolderPath,String symbol,int dayCount,int index,int penIndex,int noiseIndex,TestCase.CaseType caseType,TestCase.GenerateType generateType,DateTime purchaseDate)
|
private String CreateFileName(String strFolderPath,String symbol,int dayCount,int index,int penIndex,int noiseIndex,TestCase.CaseType caseType,TestCase.GenerateType generateType,DateTime purchaseDate)
|
||||||
@@ -216,6 +259,132 @@ namespace MarketData.CNNProcessing
|
|||||||
return String.Format("{0}{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}d.jpg",strFolderPath,symbol,index,penIndex,noiseIndex,caseType.ToString(),generateType.ToString(),Utility.DateToLong(purchaseDate),dayCount);
|
return String.Format("{0}{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}d.jpg",strFolderPath,symbol,index,penIndex,noiseIndex,caseType.ToString(),generateType.ToString(),Utility.DateToLong(purchaseDate),dayCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ProcessBollingerBandData item - Draws Price, K, L and Volatility
|
||||||
|
/// </summary>
|
||||||
|
///<param name="testCase">Symbol</param>
|
||||||
|
private void ProcessBollingerBandDataWithVolatility(TestCase testCase,float penWidth,double noise)
|
||||||
|
{
|
||||||
|
String symbolVolatility="^VIX";
|
||||||
|
DateGenerator dateGenerator=new DateGenerator();
|
||||||
|
|
||||||
|
int daysInPeriod=dateGenerator.DaysBetweenActual(testCase.PurchaseDate,testCase.HistDate);
|
||||||
|
daysInPeriod+=60;
|
||||||
|
Prices prices=PricingDA.GetPrices(testCase.Symbol,testCase.PurchaseDate,daysInPeriod);
|
||||||
|
Prices volatilityPrices=PricingDA.GetPrices(symbolVolatility,testCase.PurchaseDate,daysInPeriod);
|
||||||
|
BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices); // we want to grab K, L, and Close
|
||||||
|
bollingerBands=new BollingerBands(bollingerBands.Where(x=>x.Date>=testCase.HistDate).ToList());
|
||||||
|
float[] k=new float[bollingerBands.Count];
|
||||||
|
float[] l=new float[bollingerBands.Count];
|
||||||
|
float[] close=new float[bollingerBands.Count];
|
||||||
|
|
||||||
|
// Line up volatility dates with bollinger bands
|
||||||
|
DateTime minDate = bollingerBands.Min(x=>x.Date);
|
||||||
|
DateTime maxDate = bollingerBands.Max(x=>x.Date);
|
||||||
|
volatilityPrices = new Prices(volatilityPrices.Where(x=>x.Date<=maxDate && x.Date>=minDate).OrderBy(x=>x.Date).ToList()); // most historical date in lowest index
|
||||||
|
float[] v=volatilityPrices.GetPrices();
|
||||||
|
float minV=Numerics.Min(ref v); // get the minimum volatility value
|
||||||
|
double minP=bollingerBands.Min(x=>x.Close); // get minimum price
|
||||||
|
double factor=minP/minV; // determine scaling factor
|
||||||
|
for(int index=0;index<v.Length;index++)
|
||||||
|
{
|
||||||
|
double item = v[index];
|
||||||
|
item*=factor;
|
||||||
|
v[index]=(float)Math.Log(item)*1000.00f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate the arrays in reverse order so that we have the most historical date in the lowest index
|
||||||
|
for(int index=bollingerBands.Count-1;index>=0;index--)
|
||||||
|
{
|
||||||
|
BollingerBandElement bollingerBandElement=bollingerBands[index];
|
||||||
|
k[bollingerBands.Count-index-1]=(float)Math.Log(bollingerBandElement.K)*1000.00f; // put the data in log form
|
||||||
|
l[bollingerBands.Count-index-1]=(float)Math.Log(bollingerBandElement.L)*1000.00f; // put the data in log form
|
||||||
|
close[bollingerBands.Count-index-1]=(float)Math.Log(bollingerBandElement.Close)*1000.00f; // put the data in log form
|
||||||
|
}
|
||||||
|
Numerics.ZeroForNaNOrInfinity(ref k);
|
||||||
|
Numerics.ZeroForNaNOrInfinity(ref l);
|
||||||
|
Numerics.ZeroForNaNOrInfinity(ref close);
|
||||||
|
Numerics.ZeroForNaNOrInfinity(ref v);
|
||||||
|
float maxY=Math.Max(Math.Max(Numerics.Max(ref l),Math.Max(Numerics.Max(ref close),Numerics.Max(ref k))),Numerics.Max(ref v));
|
||||||
|
float minY=Math.Min(Math.Min(Numerics.Min(ref l),Math.Min(Numerics.Min(ref close),Numerics.Min(ref k))),Numerics.Min(ref v))-5f;
|
||||||
|
float maxX=close.Length;
|
||||||
|
float minX=0.00f;
|
||||||
|
|
||||||
|
Pen pen=new Pen(DrawingBrush,penWidth);
|
||||||
|
Pen redPen=new Pen(DrawingBrushRed,penWidth);
|
||||||
|
ImageHelper imageHelper=new ImageHelper();
|
||||||
|
|
||||||
|
PointMapping pointMapping=new PointMapping(Width,Height,maxX,minX,maxY,minY);
|
||||||
|
imageHelper.CreateImage(Width,Height,pointMapping);
|
||||||
|
imageHelper.Fill(FillBrush);
|
||||||
|
|
||||||
|
LineSegments lineSegments=new LineSegments();
|
||||||
|
// draw volatility
|
||||||
|
for(int index=0;index<v.Length;index++)
|
||||||
|
{
|
||||||
|
if(0==index)continue;
|
||||||
|
Point p1=new Point(index-1,(int)v[index-1]);
|
||||||
|
Point p2=new Point(index,(int)v[index]);
|
||||||
|
lineSegments.Add(p1,p2);
|
||||||
|
}
|
||||||
|
imageHelper.DrawPath(redPen,lineSegments);
|
||||||
|
|
||||||
|
// draw prices
|
||||||
|
lineSegments.Clear();
|
||||||
|
for(int index=0;index<close.Length && DrawPrice;index++)
|
||||||
|
{
|
||||||
|
if(0==index)continue;
|
||||||
|
Point p1=new Point(index-1,(int)close[index-1]);
|
||||||
|
Point p2=new Point(index,(int)close[index]);
|
||||||
|
lineSegments.Add(p1,p2);
|
||||||
|
}
|
||||||
|
imageHelper.DrawPath(pen,lineSegments);
|
||||||
|
// draw k
|
||||||
|
lineSegments.Clear();
|
||||||
|
for(int index=0;index<k.Length;index++)
|
||||||
|
{
|
||||||
|
if(0==index)continue;
|
||||||
|
Point p1=new Point(index-1,(int)k[index-1]);
|
||||||
|
Point p2=new Point(index,(int)k[index]);
|
||||||
|
lineSegments.Add(p1,p2);
|
||||||
|
}
|
||||||
|
imageHelper.DrawPath(pen,lineSegments);
|
||||||
|
|
||||||
|
// draw l
|
||||||
|
lineSegments.Clear();
|
||||||
|
for(int index=0;index<l.Length;index++)
|
||||||
|
{
|
||||||
|
if(0==index)continue;
|
||||||
|
Point p1=new Point(index-1,(int)l[index-1]);
|
||||||
|
Point p2=new Point(index,(int)l[index]);
|
||||||
|
lineSegments.Add(p1,p2);
|
||||||
|
}
|
||||||
|
imageHelper.DrawPath(pen,lineSegments);
|
||||||
|
|
||||||
|
|
||||||
|
if(0.00!=noise)imageHelper.AddNoise(NoiseColor,noise);
|
||||||
|
if(testCase.TypeOutput.Equals(TestCase.OutputType.OutputFile))
|
||||||
|
{
|
||||||
|
MDTrace.WriteLine(LogLevel.DEBUG,$"Writing {testCase.LastPathFileName}");
|
||||||
|
if(File.Exists(testCase.LastPathFileName))File.Delete(testCase.LastPathFileName);
|
||||||
|
if(UseGrayScale)imageHelper.SaveGrayScaleJPG(testCase.LastPathFileName);
|
||||||
|
else imageHelper.Save(testCase.LastPathFileName);
|
||||||
|
// else imageHelper.SaveBlackAndWhiteJPG(testCase.LastPathFileName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
testCase.Streams.Add(imageHelper.ToStream());
|
||||||
|
// testCase.Streams.Add(imageHelper.SaveBlackAndWhiteJPG());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate Bollinger Band Data
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testCase"></param>
|
||||||
|
/// <param name="movingAverageDays"></param>
|
||||||
|
/// <param name="penWidth"></param>
|
||||||
|
/// <param name="noise"></param>
|
||||||
private void ProcessBollingerBandData(TestCase testCase,int movingAverageDays,float penWidth,double noise)
|
private void ProcessBollingerBandData(TestCase testCase,int movingAverageDays,float penWidth,double noise)
|
||||||
{
|
{
|
||||||
int bufferDays=60;
|
int bufferDays=60;
|
||||||
@@ -377,6 +546,7 @@ namespace MarketData.CNNProcessing
|
|||||||
|
|
||||||
if(testCase.TypeOutput.Equals(TestCase.OutputType.OutputFile))
|
if(testCase.TypeOutput.Equals(TestCase.OutputType.OutputFile))
|
||||||
{
|
{
|
||||||
|
MDTrace.WriteLine(LogLevel.DEBUG,$"Writing {testCase.LastPathFileName}");
|
||||||
if(File.Exists(testCase.LastPathFileName))File.Delete(testCase.LastPathFileName);
|
if(File.Exists(testCase.LastPathFileName))File.Delete(testCase.LastPathFileName);
|
||||||
if(UseGrayScale)imageHelper.SaveGrayScaleJPG(testCase.LastPathFileName);
|
if(UseGrayScale)imageHelper.SaveGrayScaleJPG(testCase.LastPathFileName);
|
||||||
else imageHelper.SaveBlackAndWhiteJPG(testCase.LastPathFileName);
|
else imageHelper.SaveBlackAndWhiteJPG(testCase.LastPathFileName);
|
||||||
@@ -426,6 +596,7 @@ namespace MarketData.CNNProcessing
|
|||||||
|
|
||||||
if(testCase.TypeOutput.Equals(TestCase.OutputType.OutputFile))
|
if(testCase.TypeOutput.Equals(TestCase.OutputType.OutputFile))
|
||||||
{
|
{
|
||||||
|
MDTrace.WriteLine(LogLevel.DEBUG,$"Writing {testCase.LastPathFileName}");
|
||||||
if(File.Exists(testCase.LastPathFileName))File.Delete(testCase.LastPathFileName);
|
if(File.Exists(testCase.LastPathFileName))File.Delete(testCase.LastPathFileName);
|
||||||
if(UseGrayScale)imageHelper.SaveGrayScaleJPG(testCase.LastPathFileName);
|
if(UseGrayScale)imageHelper.SaveGrayScaleJPG(testCase.LastPathFileName);
|
||||||
else imageHelper.SaveBlackAndWhiteJPG(testCase.LastPathFileName);
|
else imageHelper.SaveBlackAndWhiteJPG(testCase.LastPathFileName);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace MarketData.CNNProcessing
|
|||||||
public class TestCase
|
public class TestCase
|
||||||
{
|
{
|
||||||
public enum CaseType{Training,Test,Validation};
|
public enum CaseType{Training,Test,Validation};
|
||||||
public enum GenerateType{Price,BollingerBand};
|
public enum GenerateType{Price,BollingerBand,BollingerBandWithVIX};
|
||||||
public enum OutputType{OutputFile,OutputStream}
|
public enum OutputType{OutputFile,OutputStream}
|
||||||
private readonly List<Stream> streams=new List<Stream>();
|
private readonly List<Stream> streams=new List<Stream>();
|
||||||
private readonly List<String> pathFileNames=new List<String>();
|
private readonly List<String> pathFileNames=new List<String>();
|
||||||
|
|||||||
@@ -1,323 +1,260 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using MarketData.MarketDataModel;
|
using MarketData.MarketDataModel;
|
||||||
|
using MarketData.DataAccess;
|
||||||
using MarketData.Utils;
|
using MarketData.Utils;
|
||||||
|
using System.Linq;
|
||||||
using MarketData.Helper;
|
using MarketData.Helper;
|
||||||
using MarketData.Numerical;
|
using MarketData.Numerical;
|
||||||
using MarketData.DataAccess;
|
using System.Threading;
|
||||||
|
|
||||||
|
|
||||||
|
// This cache is mainly used by the models. It is a short lived cache that gets cleared out every 2 minutes.
|
||||||
|
// This cache will attempt to load a price from the database if it is found in the cache.
|
||||||
namespace MarketData.Cache
|
namespace MarketData.Cache
|
||||||
{
|
{
|
||||||
public interface IPricingDataAccess
|
public class GBPriceCache
|
||||||
{
|
{
|
||||||
Price GetPrice(string symbol, DateTime date);
|
private Thread cacheMonitorThread=null;
|
||||||
Prices GetPrices(string symbol, DateTime maxDate, DateTime minDate);
|
private volatile bool threadRun=true;
|
||||||
DateTime GetLatestDateOnOrBefore(string symbol, DateTime date);
|
private Object thisLock=new Object();
|
||||||
}
|
private Dictionary<String,PricesByDate> priceCache=new Dictionary<String,PricesByDate>(); // the main cache
|
||||||
|
private Dictionary<String,Price> realTimePriceCache=new Dictionary<String,Price>(); // short lived cache of realtime prices gets cleared out every cacheRefreshAfter(ms)
|
||||||
internal class RealPricingDA : IPricingDataAccess
|
private Dictionary<String,bool> nullCache=new Dictionary<String,bool>();
|
||||||
{
|
private DateGenerator dateGenerator=new DateGenerator();
|
||||||
public Price GetPrice(string symbol, DateTime date) => PricingDA.GetPrice(symbol, date);
|
private static GBPriceCache priceCacheInstance=null;
|
||||||
public Prices GetPrices(string symbol, DateTime maxDate, DateTime minDate) => PricingDA.GetPrices(symbol, maxDate, minDate);
|
private int cacheRefreshAfter=120000; // the cache will be cleaned up after 2 minutes
|
||||||
public DateTime GetLatestDateOnOrBefore(string symbol, DateTime date) => PricingDA.GetLatestDateOnOrBefore(symbol, date);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class CacheSnapshot
|
|
||||||
{
|
|
||||||
public Dictionary<String, PricesByDate> PriceCache { get; }
|
|
||||||
public Dictionary<String, Price> RealTimePriceCache { get; }
|
|
||||||
public Dictionary<String, bool> NullCache { get; }
|
|
||||||
|
|
||||||
public CacheSnapshot(
|
|
||||||
Dictionary<String, PricesByDate> priceCache,
|
|
||||||
Dictionary<String, Price> realTimePriceCache,
|
|
||||||
Dictionary<String, bool> nullCache)
|
|
||||||
{
|
|
||||||
PriceCache = priceCache;
|
|
||||||
RealTimePriceCache = realTimePriceCache;
|
|
||||||
NullCache = nullCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GBPriceCache : IDisposable
|
|
||||||
{
|
|
||||||
private Thread cacheMonitorThread = null;
|
|
||||||
private volatile bool threadRun = true;
|
|
||||||
private Object thisLock = new Object();
|
|
||||||
|
|
||||||
private CacheSnapshot snapshot;
|
|
||||||
private DateGenerator dateGenerator = new DateGenerator();
|
|
||||||
private static GBPriceCache priceCacheInstance = null;
|
|
||||||
private int cacheRefreshAfter = 120000; // 2 minutes
|
|
||||||
private SemaphoreSlim fetchSemaphore = new SemaphoreSlim(8); // max 8 concurrent DB fetches
|
|
||||||
public IPricingDataAccess PricingDataAccess { get; set; } = new RealPricingDA();
|
|
||||||
|
|
||||||
protected GBPriceCache()
|
protected GBPriceCache()
|
||||||
{
|
{
|
||||||
snapshot = new CacheSnapshot(new Dictionary<String, PricesByDate>(), new Dictionary<String, Price>(), new Dictionary<String, bool>());
|
cacheMonitorThread=new Thread(new ThreadStart(ThreadProc));
|
||||||
cacheMonitorThread = new Thread(new ThreadStart(ThreadProc));
|
|
||||||
cacheMonitorThread.Start();
|
cacheMonitorThread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GBPriceCache GetInstance()
|
public static GBPriceCache GetInstance()
|
||||||
{
|
{
|
||||||
lock (typeof(GBPriceCache))
|
lock(typeof(GBPriceCache))
|
||||||
{
|
{
|
||||||
if (null == priceCacheInstance)
|
if(null==priceCacheInstance)
|
||||||
{
|
{
|
||||||
priceCacheInstance = new GBPriceCache();
|
priceCacheInstance=new GBPriceCache();
|
||||||
}
|
}
|
||||||
return priceCacheInstance;
|
return priceCacheInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
lock (thisLock)
|
lock(thisLock)
|
||||||
{
|
{
|
||||||
snapshot = new CacheSnapshot(new Dictionary<String, PricesByDate>(), new Dictionary<String, Price>(), new Dictionary<String, bool>());
|
priceCache=new Dictionary<String,PricesByDate>();
|
||||||
|
realTimePriceCache=new Dictionary<String,Price>();
|
||||||
|
nullCache=new Dictionary<String,bool>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
lock (thisLock)
|
lock(thisLock)
|
||||||
{
|
{
|
||||||
if (null == priceCacheInstance || !threadRun) return;
|
if(null==priceCacheInstance || false==threadRun)return;
|
||||||
threadRun = false;
|
threadRun=false;
|
||||||
if (null != cacheMonitorThread)
|
if(null!=cacheMonitorThread)
|
||||||
{
|
{
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG, "[GBPriceCache:Dispose] Joining monitor thread...");
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("[GBPriceCache:Dispose]Thread state is '{0}'. Joining main thread...",Utility.ThreadStateToString(cacheMonitorThread)));
|
||||||
cacheMonitorThread.Join(5000);
|
cacheMonitorThread.Join(5000);
|
||||||
cacheMonitorThread = null;
|
this.cacheMonitorThread=null;
|
||||||
}
|
}
|
||||||
priceCacheInstance = null;
|
MDTrace.WriteLine(LogLevel.DEBUG,"[GBPriceCache:Dispose] End.");
|
||||||
|
priceCacheInstance=null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void ClearCacheOnOrBefore(DateTime onOrBeforeDate,bool collect=false)
|
||||||
public void ClearCacheOnOrBefore(DateTime onOrBeforeDate, bool collect = false)
|
|
||||||
{
|
{
|
||||||
lock (thisLock)
|
lock(thisLock)
|
||||||
{
|
{
|
||||||
Dictionary<String, PricesByDate> newPriceCache = new Dictionary<String, PricesByDate>();
|
MDTrace.WriteLine(LogLevel.DEBUG,"Clearing GBPriceCache cache.");
|
||||||
foreach (KeyValuePair<String, PricesByDate> entry in snapshot.PriceCache)
|
List<String> symbols=new List<String>(priceCache.Keys);
|
||||||
|
foreach(String symbol in symbols)
|
||||||
{
|
{
|
||||||
String symbol = entry.Key;
|
PricesByDate pricesByDate=priceCache[symbol];
|
||||||
PricesByDate filteredPrices = new PricesByDate();
|
List<DateTime> symbolDates=new List<DateTime>(pricesByDate.Keys);
|
||||||
PricesByDate existingPrices = entry.Value;
|
foreach(DateTime symbolDate in symbolDates)
|
||||||
foreach (KeyValuePair<DateTime, Price> kvp in existingPrices)
|
|
||||||
{
|
{
|
||||||
if (kvp.Key >= onOrBeforeDate)
|
if(symbolDate<onOrBeforeDate) pricesByDate.Remove(symbolDate);
|
||||||
{
|
|
||||||
filteredPrices.Add(kvp.Key, kvp.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (filteredPrices.Count > 0)
|
|
||||||
{
|
|
||||||
newPriceCache.Add(symbol, filteredPrices);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UpdateSnapshot(newPriceCache, snapshot.RealTimePriceCache, snapshot.NullCache);
|
MDTrace.WriteLine(LogLevel.DEBUG,"Calling garbage collector...");
|
||||||
if (collect) GC.Collect();
|
if(collect) GC.Collect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Price GetPriceOrLatestAvailable(String symbol, DateTime date)
|
public Price GetPriceOrLatestAvailable(String symbol,DateTime date)
|
||||||
{
|
{
|
||||||
Price price = GetPrice(symbol, date);
|
lock(thisLock)
|
||||||
if (null != price) return price;
|
|
||||||
DateTime latestPricingDate = PricingDataAccess.GetLatestDateOnOrBefore(symbol, date);
|
|
||||||
price = GetPrice(symbol, latestPricingDate);
|
|
||||||
if (null != price) return price;
|
|
||||||
fetchSemaphore.Wait();
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
price = PricingDataAccess.GetPrice(symbol, latestPricingDate);
|
Price price=GetPrice(symbol,date);
|
||||||
|
if(null!=price) return price;
|
||||||
|
DateTime latestPricingDate=PricingDA.GetLatestDateOnOrBefore(symbol,date);
|
||||||
|
price=GetPrice(symbol,latestPricingDate);
|
||||||
|
if(null!=price) return price;
|
||||||
|
price=PricingDA.GetPrice(symbol,latestPricingDate);
|
||||||
|
if(null!=price) AddPrice(price);
|
||||||
|
return price;
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
fetchSemaphore.Release();
|
|
||||||
}
|
|
||||||
if (null !=price) AddPrice(price);
|
|
||||||
return price;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Price GetRealtimePrice(String symbol)
|
public Price GetRealtimePrice(String symbol)
|
||||||
{
|
{
|
||||||
if (snapshot.RealTimePriceCache.ContainsKey(symbol))
|
if(realTimePriceCache.ContainsKey(symbol)) return realTimePriceCache[symbol];
|
||||||
|
Price price=MarketDataHelper.GetLatestPrice(symbol);
|
||||||
|
if(null!=price)
|
||||||
{
|
{
|
||||||
return snapshot.RealTimePriceCache[symbol];
|
realTimePriceCache.Add(symbol,price);
|
||||||
}
|
|
||||||
|
|
||||||
Price price = MarketDataHelper.GetLatestPrice(symbol);
|
|
||||||
if (null != price)
|
|
||||||
{
|
|
||||||
Dictionary<String, Price> newRealtime = new Dictionary<String, Price>(snapshot.RealTimePriceCache);
|
|
||||||
newRealtime.Add(symbol, price);
|
|
||||||
UpdateSnapshot(snapshot.PriceCache, newRealtime, snapshot.NullCache);
|
|
||||||
}
|
}
|
||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
public Price GetPrice(String symbol,DateTime date)
|
||||||
public Price GetPrice(String symbol, DateTime date)
|
|
||||||
{
|
{
|
||||||
date = date.Date;
|
lock(thisLock)
|
||||||
if (!ContainsPrice(symbol, date))
|
|
||||||
{
|
{
|
||||||
String key = symbol + Utility.DateTimeToStringMMHDDHYYYY(date);
|
date=date.Date;
|
||||||
if (snapshot.NullCache.ContainsKey(key))
|
if(!ContainsPrice(symbol,date))
|
||||||
{
|
{
|
||||||
return null;
|
String key=symbol+Utility.DateTimeToStringMMHDDHYYYY(date);
|
||||||
|
if(nullCache.ContainsKey(key)) return null;
|
||||||
|
Price price=PricingDA.GetPrice(symbol,date);
|
||||||
|
if(null==price)
|
||||||
|
{
|
||||||
|
nullCache.Add(key,true);
|
||||||
|
return price;
|
||||||
|
}
|
||||||
|
AddPrice(price);
|
||||||
}
|
}
|
||||||
fetchSemaphore.Wait();
|
if(!priceCache.ContainsKey(symbol)) return null;
|
||||||
Price price;
|
PricesByDate pricesByDate=priceCache[symbol];
|
||||||
try
|
if(!pricesByDate.ContainsKey(date.Date)) return null;
|
||||||
{
|
return pricesByDate[date];
|
||||||
price = PricingDataAccess.GetPrice(symbol, date);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
fetchSemaphore.Release();
|
|
||||||
}
|
|
||||||
if (null ==price)
|
|
||||||
{
|
|
||||||
Dictionary<String, bool> newNullCache = new Dictionary<String, bool>(snapshot.NullCache);
|
|
||||||
newNullCache.Add(key, true);
|
|
||||||
UpdateSnapshot(snapshot.PriceCache, snapshot.RealTimePriceCache, newNullCache);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddPrice(price);
|
|
||||||
}
|
}
|
||||||
if (!snapshot.PriceCache.ContainsKey(symbol)) return null;
|
|
||||||
PricesByDate pricesByDate = snapshot.PriceCache[symbol];
|
|
||||||
if (!pricesByDate.ContainsKey(date)) return null;
|
|
||||||
return pricesByDate[date];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Prices GetPrices(String symbol, DateTime earlierDate, DateTime laterDate)
|
public Prices GetPrices(String symbol, DateTime earlierDate, DateTime laterDate)
|
||||||
{
|
{
|
||||||
DateGenerator localDateGenerator = new DateGenerator();
|
DateGenerator dateGenerator = new DateGenerator();
|
||||||
if (laterDate < earlierDate)
|
|
||||||
|
if(laterDate<earlierDate)
|
||||||
{
|
{
|
||||||
DateTime tempDate = earlierDate;
|
DateTime tempDate = earlierDate;
|
||||||
earlierDate = laterDate;
|
earlierDate = laterDate;
|
||||||
laterDate = tempDate;
|
laterDate=tempDate;
|
||||||
}
|
}
|
||||||
List<DateTime> datesList = localDateGenerator.GenerateHistoricalDates(earlierDate, laterDate);
|
List<DateTime> datesList = dateGenerator.GenerateHistoricalDates(earlierDate, laterDate);
|
||||||
datesList = datesList.Where(x => x >= earlierDate).ToList();
|
datesList = datesList.Where(x => x >= earlierDate).ToList();
|
||||||
return GetPrices(symbol, laterDate, datesList.Count);
|
return GetPrices(symbol, laterDate, datesList.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Prices GetPrices(String symbol, DateTime startDate, int dayCount)
|
// The most recent price is returned at the lowest index
|
||||||
|
public Prices GetPrices(String symbol,DateTime startDate,int dayCount)
|
||||||
{
|
{
|
||||||
List<DateTime> historicalDates = dateGenerator.GenerateHistoricalDates(startDate, dayCount + 60);
|
lock(thisLock)
|
||||||
List<DateTime> missingDates = new List<DateTime>();
|
|
||||||
foreach (DateTime historicalDate in historicalDates)
|
|
||||||
{
|
{
|
||||||
if (!ContainsPrice(symbol, historicalDate))
|
List<DateTime> historicalDates=dateGenerator.GenerateHistoricalDates(startDate,dayCount+60);
|
||||||
|
Prices prices=null;
|
||||||
|
List<DateTime> missingDates=null;
|
||||||
|
foreach(DateTime historicalDate in historicalDates)
|
||||||
{
|
{
|
||||||
String key = symbol + Utility.DateTimeToStringMMHDDHYYYY(historicalDate);
|
if(!ContainsPrice(symbol,historicalDate))
|
||||||
if (!snapshot.NullCache.ContainsKey(key))
|
|
||||||
{
|
{
|
||||||
|
String key=symbol+Utility.DateTimeToStringMMHDDHYYYY(historicalDate);
|
||||||
|
if(nullCache.ContainsKey(key)) continue;
|
||||||
|
if(null==missingDates)missingDates=new List<DateTime>();
|
||||||
missingDates.Add(historicalDate);
|
missingDates.Add(historicalDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if(null!=missingDates)
|
||||||
if (missingDates.Count > 0)
|
|
||||||
{
|
|
||||||
DateTime minDate = missingDates.Min();
|
|
||||||
DateTime maxDate = missingDates.Max();
|
|
||||||
|
|
||||||
fetchSemaphore.Wait();
|
|
||||||
Prices loadedPrices;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
loadedPrices = PricingDataAccess.GetPrices(symbol, maxDate, minDate);
|
DateTime minDate=(from DateTime date in missingDates select date).Min();
|
||||||
}
|
DateTime maxDate=(from DateTime date in missingDates select date).Max();
|
||||||
finally
|
prices=PricingDA.GetPrices(symbol,maxDate,minDate);
|
||||||
{
|
foreach(Price price in prices) AddPrice(price);
|
||||||
fetchSemaphore.Release();
|
prices=new Prices();
|
||||||
}
|
foreach(DateTime historicalDate in historicalDates)
|
||||||
|
{
|
||||||
foreach (Price price in loadedPrices)
|
if(!ContainsPrice(symbol,historicalDate))
|
||||||
{
|
{
|
||||||
AddPrice(price);
|
String key=symbol+Utility.DateTimeToStringMMHDDHYYYY(historicalDate);
|
||||||
}
|
if(!nullCache.ContainsKey(key)) nullCache.Add(key,true);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
Prices prices = new Prices();
|
{
|
||||||
foreach (DateTime historicalDate in historicalDates)
|
if(!priceCache.ContainsKey(symbol)) continue;
|
||||||
{
|
PricesByDate pricesByDate=priceCache[symbol];
|
||||||
if (!snapshot.PriceCache.ContainsKey(symbol)) continue;
|
if(!pricesByDate.ContainsKey(historicalDate.Date)) continue;
|
||||||
PricesByDate pricesByDate = snapshot.PriceCache[symbol];
|
prices.Add(pricesByDate[historicalDate]);
|
||||||
if (!pricesByDate.ContainsKey(historicalDate)) continue;
|
}
|
||||||
prices.Add(pricesByDate[historicalDate]);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
List<Price> ordered = prices.OrderByDescending(x => x.Date).ToList();
|
|
||||||
return new Prices(ordered.Take(dayCount).ToList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddPrice(Price price)
|
|
||||||
{
|
|
||||||
if (null == price) return;
|
|
||||||
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
|
||||||
PricesByDate pricesByDate;
|
|
||||||
if (!snapshot.PriceCache.ContainsKey(price.Symbol))
|
|
||||||
{
|
|
||||||
pricesByDate = new PricesByDate();
|
|
||||||
pricesByDate.Add(price.Date, price);
|
|
||||||
Dictionary<String, PricesByDate> newCache = new Dictionary<String, PricesByDate>(snapshot.PriceCache);
|
|
||||||
newCache.Add(price.Symbol, pricesByDate);
|
|
||||||
UpdateSnapshot(newCache, snapshot.RealTimePriceCache, snapshot.NullCache);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pricesByDate = snapshot.PriceCache[price.Symbol];
|
prices=new Prices();
|
||||||
if (!pricesByDate.ContainsKey(price.Date))
|
foreach(DateTime historicalDate in historicalDates)
|
||||||
{
|
{
|
||||||
pricesByDate.Add(price.Date, price);
|
if(!priceCache.ContainsKey(symbol)) continue;
|
||||||
|
if(!priceCache[symbol].ContainsKey(historicalDate.Date))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
prices.Add((priceCache[symbol])[historicalDate]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return new Prices(prices.OrderByDescending(x => x.Date).ToList().Take(dayCount).ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void AddPrice(Price price)
|
||||||
|
{
|
||||||
|
lock(thisLock)
|
||||||
|
{
|
||||||
|
if(null==price) return;
|
||||||
|
PricesByDate pricesByDate=null;
|
||||||
|
if(!priceCache.ContainsKey(price.Symbol))
|
||||||
|
{
|
||||||
|
pricesByDate=new PricesByDate();
|
||||||
|
pricesByDate.Add(price.Date,price);
|
||||||
|
priceCache.Add(price.Symbol,pricesByDate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pricesByDate=priceCache[price.Symbol];
|
||||||
|
if(pricesByDate.ContainsKey(price.Date.Date)) return;
|
||||||
|
pricesByDate.Add(price.Date.Date,price);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public bool ContainsPrice(String symbol,DateTime date)
|
||||||
public bool ContainsPrice(String symbol, DateTime date)
|
|
||||||
{
|
{
|
||||||
if (!snapshot.PriceCache.ContainsKey(symbol)) return false;
|
if(!priceCache.ContainsKey(symbol)) return false;
|
||||||
PricesByDate pricesByDate = snapshot.PriceCache[symbol];
|
PricesByDate pricesByDate=priceCache[symbol];
|
||||||
return pricesByDate.ContainsKey(date);
|
if(!pricesByDate.ContainsKey(date.Date)) return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThreadProc()
|
private void ThreadProc()
|
||||||
{
|
{
|
||||||
int quantums = 0;
|
int quantums=0;
|
||||||
int quantumInterval = 1000;
|
int quantumInterval=1000;
|
||||||
|
while(threadRun)
|
||||||
while (threadRun)
|
|
||||||
{
|
{
|
||||||
Thread.Sleep(quantumInterval);
|
Thread.Sleep(quantumInterval);
|
||||||
if(!threadRun)break;
|
if(!threadRun) break;
|
||||||
quantums += quantumInterval;
|
quantums+=quantumInterval;
|
||||||
if (quantums > cacheRefreshAfter)
|
if(quantums>cacheRefreshAfter)
|
||||||
{
|
{
|
||||||
quantums = 0;
|
quantums=0;
|
||||||
lock (thisLock)
|
lock(thisLock)
|
||||||
{
|
{
|
||||||
UpdateSnapshot(snapshot.PriceCache, new Dictionary<String, Price>(), snapshot.NullCache);
|
realTimePriceCache.Clear();
|
||||||
|
MDTrace.WriteLine(LogLevel.DEBUG,"Clearing GBPriceCache price cache.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
MDTrace.WriteLine(LogLevel.DEBUG,"[GBPriceCache:ThreadProc]Thread ended.");
|
||||||
|
|
||||||
private void UpdateSnapshot(Dictionary<String, PricesByDate> newPriceCache,Dictionary<String, Price> newRealtimePriceCache, Dictionary<String, bool> newNullCache)
|
|
||||||
{
|
|
||||||
snapshot = new CacheSnapshot(newPriceCache, newRealtimePriceCache, newNullCache);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,70 +1,65 @@
|
|||||||
using MarketData.MarketDataModel;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using MarketData.MarketDataModel;
|
||||||
using MarketData.Utils;
|
using MarketData.Utils;
|
||||||
using MarketData.DataAccess;
|
using MarketData.DataAccess;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
|
// This cache is mainly used by gainloss generator. This cache is intended to be front loaded and then used.
|
||||||
|
// This cache will not attempt to load an item that is not found. It does have a Refresh() that will reload only the most recent pricing data from the database in order to
|
||||||
|
// maintain the most updated pricing.
|
||||||
namespace MarketData.Cache
|
namespace MarketData.Cache
|
||||||
{
|
{
|
||||||
public class LocalPriceCache
|
public class LocalPriceCache
|
||||||
{
|
{
|
||||||
private Dictionary<string, PricesByDate> priceCache = new Dictionary<string, PricesByDate>();
|
private Dictionary<String,PricesByDate> priceCache=new Dictionary<String,PricesByDate>();
|
||||||
private static LocalPriceCache instance = null;
|
private static LocalPriceCache instance=null;
|
||||||
private DateTime latestDate = Utility.Epoch;
|
private DateTime latestDate = Utility.Epoch;
|
||||||
private Thread cacheMonitorThread = null;
|
private Thread cacheMonitorThread=null;
|
||||||
private volatile bool threadRun = true;
|
private volatile bool threadRun=true;
|
||||||
private int cacheCycle = 300000;
|
private int cacheCycle=300000;
|
||||||
private object thisLock = new object();
|
private Object thisLock=new Object();
|
||||||
private object fetchLock = new object();
|
|
||||||
|
|
||||||
private LocalPriceCache()
|
private LocalPriceCache()
|
||||||
{
|
{
|
||||||
cacheMonitorThread = new Thread(new ThreadStart(ThreadProc));
|
cacheMonitorThread=new Thread(new ThreadStart(ThreadProc));
|
||||||
cacheMonitorThread.Start();
|
cacheMonitorThread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
lock (thisLock)
|
lock(thisLock)
|
||||||
{
|
{
|
||||||
priceCache = new Dictionary<string, PricesByDate>();
|
priceCache=new Dictionary<String,PricesByDate>();
|
||||||
RefreshLatestDate();
|
RefreshLatestDate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Thread threadToJoin = null;
|
lock(thisLock)
|
||||||
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
{
|
||||||
if (instance == null || !threadRun) return;
|
if(null==instance || false==threadRun)return;
|
||||||
threadRun = false;
|
threadRun=false;
|
||||||
threadToJoin = cacheMonitorThread;
|
if(null!=cacheMonitorThread)
|
||||||
cacheMonitorThread = null;
|
{
|
||||||
instance = null;
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("[LocalPriceCache:Dispose]Thread state is '{0}'. Joining main thread...",Utility.ThreadStateToString(cacheMonitorThread)));
|
||||||
|
cacheMonitorThread.Join(5000);
|
||||||
|
this.cacheMonitorThread=null;
|
||||||
|
}
|
||||||
|
MDTrace.WriteLine(LogLevel.DEBUG,"[LocalPriceCache:Dispose] End");
|
||||||
|
instance=null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (threadToJoin != null)
|
|
||||||
{
|
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG, $"[LocalPriceCache:Dispose] Thread state is '{Utility.ThreadStateToString(threadToJoin)}'. Joining...");
|
|
||||||
threadToJoin.Join(5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG, "[LocalPriceCache:Dispose] End");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocalPriceCache GetInstance()
|
public static LocalPriceCache GetInstance()
|
||||||
{
|
{
|
||||||
lock (typeof(LocalPriceCache))
|
lock(typeof(LocalPriceCache))
|
||||||
{
|
{
|
||||||
if (instance == null)
|
if(null==instance)
|
||||||
{
|
{
|
||||||
instance = new LocalPriceCache();
|
instance=new LocalPriceCache();
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@@ -72,17 +67,17 @@ namespace MarketData.Cache
|
|||||||
|
|
||||||
public void RefreshLatestDate()
|
public void RefreshLatestDate()
|
||||||
{
|
{
|
||||||
lock (thisLock)
|
lock(typeof(LocalPriceCache))
|
||||||
{
|
{
|
||||||
latestDate = PricingDA.GetLatestDate();
|
latestDate=PricingDA.GetLatestDate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime GetLatestDate()
|
public DateTime GetLatestDate()
|
||||||
{
|
{
|
||||||
lock (thisLock)
|
lock(typeof(LocalPriceCache))
|
||||||
{
|
{
|
||||||
if (Utility.IsEpoch(latestDate))
|
if(Utility.IsEpoch(latestDate))
|
||||||
{
|
{
|
||||||
RefreshLatestDate();
|
RefreshLatestDate();
|
||||||
}
|
}
|
||||||
@@ -92,118 +87,65 @@ namespace MarketData.Cache
|
|||||||
|
|
||||||
public void Refresh()
|
public void Refresh()
|
||||||
{
|
{
|
||||||
List<string> symbols;
|
lock(typeof(LocalPriceCache))
|
||||||
Dictionary<string, DateTime> currentMaxDates;
|
|
||||||
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
{
|
||||||
symbols = priceCache.Keys.ToList();
|
List<String> symbols=new List<String>(priceCache.Keys);
|
||||||
currentMaxDates = priceCache.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.MaxDate);
|
Dictionary<String, DateTime> maxDbDates = PricingDA.GetLatestDates(symbols);
|
||||||
}
|
RefreshLatestDate();
|
||||||
|
foreach(String symbol in symbols)
|
||||||
if (symbols.Count == 0) return;
|
|
||||||
|
|
||||||
ConcurrentDictionary<string, PricesByDate> fullReloads = new ConcurrentDictionary<string, PricesByDate>();
|
|
||||||
ConcurrentDictionary<string, Price> singleUpdates = new ConcurrentDictionary<string, Price>();
|
|
||||||
DateTime latestDateFromDb;
|
|
||||||
|
|
||||||
lock (fetchLock)
|
|
||||||
{
|
|
||||||
Dictionary<string, DateTime> maxDbDates = PricingDA.GetLatestDates(symbols);
|
|
||||||
latestDateFromDb = PricingDA.GetLatestDate();
|
|
||||||
|
|
||||||
Parallel.ForEach(symbols, new ParallelOptions { MaxDegreeOfParallelism = 8 }, symbol =>
|
|
||||||
{
|
{
|
||||||
if (!currentMaxDates.TryGetValue(symbol, out var cachedMax)) return;
|
PricesByDate symbolPrices=priceCache[symbol];
|
||||||
|
DateTime maxDate=symbolPrices.MaxDate; // get the latest date in the cache
|
||||||
if (maxDbDates.TryGetValue(symbol, out var dbMax) && dbMax.Date != cachedMax.Date)
|
if(maxDbDates.ContainsKey(symbol) && !maxDbDates[symbol].Date.Equals(maxDate.Date)) // if the cache date and the database date are not equal then reload the cache
|
||||||
{
|
{
|
||||||
Prices prices = PricingDA.GetPrices(symbol, cachedMax);
|
MDTrace.WriteLine(LogLevel.DEBUG,$"Cache date and Database date for {symbol} are not equal, reloading cache. Cache Date:{maxDate.ToShortDateString()} Database Date:{maxDbDates[symbol].Date.ToShortDateString()}");
|
||||||
if (prices != null) fullReloads[symbol] = prices.GetPricesByDate();
|
Prices prices=PricingDA.GetPrices(symbol,symbolPrices.MinDate); // reload the prices for this symbol using the current minDate in the cache as a lower boundary
|
||||||
|
if(null==prices)continue; // if we can't load any prices for symbol then just continue
|
||||||
|
priceCache.Remove(symbol); // remove the pricing entries in the price cache for the symbol
|
||||||
|
priceCache.Add(symbol,prices.GetPricesByDate()); // reload the cache
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Price price = PricingDA.GetPrice(symbol, cachedMax);
|
MDTrace.WriteLine(LogLevel.DEBUG,$"[LocalPriceCache] Fetching latest price from database for {symbol} on {maxDate.ToShortDateString()}");
|
||||||
if (price != null) singleUpdates[symbol] = price;
|
Price price=PricingDA.GetPrice(symbol,maxDate); // the max date from the cache equals the max date from the database so just reload the latest price from the database
|
||||||
}
|
if(null==price)continue; // if no latest price then just continue
|
||||||
});
|
symbolPrices.Remove(maxDate); // remove the current price associated with the max date
|
||||||
}
|
symbolPrices.Add(maxDate,price); // reload the latest price for maxDate(symbol) into the cache
|
||||||
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
|
||||||
latestDate = latestDateFromDb;
|
|
||||||
|
|
||||||
foreach (var kvp in fullReloads)
|
|
||||||
{
|
|
||||||
if (priceCache.TryGetValue(kvp.Key, out PricesByDate existing) && existing.MaxDate == currentMaxDates[kvp.Key])
|
|
||||||
{
|
|
||||||
priceCache[kvp.Key] = kvp.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var kvp in singleUpdates)
|
|
||||||
{
|
|
||||||
if (priceCache.TryGetValue(kvp.Key, out PricesByDate pricesByDate) && pricesByDate.MaxDate == currentMaxDates[kvp.Key])
|
|
||||||
{
|
|
||||||
// Remove the old price (if any) and add the new price properly
|
|
||||||
if (pricesByDate.ContainsKey(kvp.Value.Date))
|
|
||||||
pricesByDate.Remove(kvp.Value.Date);
|
|
||||||
pricesByDate.Add(kvp.Value.Date, kvp.Value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG, $"Full reloads: {fullReloads.Count}, Single updates: {singleUpdates.Count}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This version of Add(PortfolioTrades) will account for adding multiple lots at different times. So instead of just checking for the existance of the symbol in the cache
|
||||||
|
// we look to see if the symbol is in the cache and what dates are available. If the date range specified in the trade are not available then we load those date ranges.
|
||||||
|
// This is a brute force approach always maintaining the gap between successive TradeDates in th.e portfolio trades and the maximum date for the symbol in the database.
|
||||||
|
// So while it is inefficient in terms of memory usage it alleviates the need for figuring out contiguous price sections
|
||||||
public void Add(PortfolioTrades portfolioTrades)
|
public void Add(PortfolioTrades portfolioTrades)
|
||||||
{
|
{
|
||||||
List<string> symbols = portfolioTrades.Symbols;
|
lock(typeof(LocalPriceCache))
|
||||||
Dictionary<string, DateTime> minTradeDates = symbols.ToDictionary(sym => sym, sym => portfolioTrades.GetMinTradeDate(sym));
|
|
||||||
|
|
||||||
Dictionary<string, DateTime> minCacheDates;
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
{
|
||||||
minCacheDates = symbols.ToDictionary(sym => sym, sym => priceCache.ContainsKey(sym) ? priceCache[sym].MinDate : DateTime.MaxValue);
|
Profiler profiler=new Profiler();
|
||||||
}
|
profiler.Start();
|
||||||
|
List<String> symbols=portfolioTrades.Symbols;
|
||||||
ConcurrentDictionary<string, Prices> fetchedPrices = new ConcurrentDictionary<string, Prices>();
|
foreach(String symbol in symbols)
|
||||||
|
|
||||||
Parallel.ForEach(symbols, new ParallelOptions { MaxDegreeOfParallelism = 8 }, symbol =>
|
|
||||||
{
|
|
||||||
DateTime minTradeDate = minTradeDates[symbol];
|
|
||||||
DateTime minCacheDate = minCacheDates[symbol];
|
|
||||||
Prices prices = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if (minCacheDate == DateTime.MaxValue)
|
DateTime minPortfolioTradeDate=portfolioTrades.GetMinTradeDate(symbol);
|
||||||
|
if(!ContainsSymbol(symbol))
|
||||||
{
|
{
|
||||||
prices = PricingDA.GetPrices(symbol, minTradeDate);
|
Prices prices=PricingDA.GetPrices(symbol,minPortfolioTradeDate);
|
||||||
|
if(null==prices)continue;
|
||||||
|
foreach(Price price in prices)Add(price);
|
||||||
}
|
}
|
||||||
else if (minTradeDate < minCacheDate)
|
else
|
||||||
{
|
{
|
||||||
prices = PricingDA.GetPrices(symbol, minCacheDate, minTradeDate);
|
DateTime minCacheDate=GetMinCacheDate(symbol);
|
||||||
}
|
if(minPortfolioTradeDate<minCacheDate)
|
||||||
|
{
|
||||||
if (prices != null && prices.Count > 0)
|
Prices prices=PricingDA.GetPrices(symbol,minCacheDate,minPortfolioTradeDate); // Fill the gap by retrieving prices starting at minCache date and going back in time to minPortfolioTradeDate
|
||||||
{
|
if(null==prices)continue;
|
||||||
fetchedPrices[symbol] = prices;
|
foreach(Price price in prices)Add(price);
|
||||||
}
|
PricesByDate p=priceCache[symbol];
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG, $"Error fetching prices for {symbol}: {ex.Message}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
|
||||||
foreach (var kvp in fetchedPrices)
|
|
||||||
{
|
|
||||||
foreach (var price in kvp.Value)
|
|
||||||
{
|
|
||||||
Add(price);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,186 +153,131 @@ namespace MarketData.Cache
|
|||||||
|
|
||||||
public void Add(Prices prices)
|
public void Add(Prices prices)
|
||||||
{
|
{
|
||||||
foreach (Price price in prices)
|
foreach(Price price in prices)
|
||||||
{
|
{
|
||||||
Add(price);
|
Add(price);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(List<string> symbols, DateTime pricingDate)
|
public void Add(List<String> symbols,DateTime pricingDate)
|
||||||
{
|
{
|
||||||
if (symbols == null || symbols.Count == 0) return;
|
foreach(String symbol in symbols)
|
||||||
|
|
||||||
ConcurrentDictionary<string, Price> fetchedPrices = new ConcurrentDictionary<string, Price>();
|
|
||||||
|
|
||||||
Parallel.ForEach(symbols, new ParallelOptions { MaxDegreeOfParallelism = 8 }, symbol =>
|
|
||||||
{
|
{
|
||||||
lock (thisLock)
|
if(ContainsPrice(symbol,pricingDate))continue;
|
||||||
{
|
Price price=PricingDA.GetPrice(symbol,pricingDate);
|
||||||
if (ContainsPrice(symbol, pricingDate)) return;
|
if(null==price)continue;
|
||||||
}
|
Add(price);
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Price price = PricingDA.GetPrice(symbol, pricingDate);
|
|
||||||
if (price != null) fetchedPrices[symbol] = price;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG, $"Error fetching price for {symbol} on {pricingDate:yyyy-MM-dd}: {ex.Message}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
|
||||||
foreach (var kvp in fetchedPrices)
|
|
||||||
{
|
|
||||||
Add(kvp.Value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(Price price)
|
public void Add(Price price)
|
||||||
{
|
{
|
||||||
if (price == null) return;
|
lock(typeof(LocalPriceCache))
|
||||||
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
{
|
||||||
if (!priceCache.TryGetValue(price.Symbol, out var pricesByDate))
|
if(null==price)return;
|
||||||
|
if(ContainsPrice(price.Symbol,price.Date))return;
|
||||||
|
PricesByDate pricesByDate=null;
|
||||||
|
if(!priceCache.ContainsKey(price.Symbol))
|
||||||
{
|
{
|
||||||
pricesByDate = new PricesByDate();
|
pricesByDate=new PricesByDate();
|
||||||
priceCache[price.Symbol] = pricesByDate;
|
pricesByDate.Add(price.Date,price);
|
||||||
}
|
priceCache.Add(price.Symbol,pricesByDate);
|
||||||
if (!pricesByDate.ContainsKey(price.Date))
|
return;
|
||||||
{
|
|
||||||
pricesByDate.Add(price.Date, price); // must use Add() to update MinDate/MaxDate
|
|
||||||
}
|
}
|
||||||
|
pricesByDate=priceCache[price.Symbol];
|
||||||
|
if(pricesByDate.ContainsKey(price.Date))return;
|
||||||
|
pricesByDate.Add(price.Date,price);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public DateTime GetMinCacheDate(String symbol)
|
||||||
public DateTime GetMinCacheDate(string symbol)
|
|
||||||
{
|
{
|
||||||
lock (thisLock)
|
if(!ContainsSymbol(symbol))return Utility.Epoch;
|
||||||
{
|
PricesByDate symbolPrices=priceCache[symbol];
|
||||||
if (!priceCache.TryGetValue(symbol, out var symbolPrices) || symbolPrices.Count == 0)
|
return symbolPrices.MinDate;
|
||||||
{
|
|
||||||
return Utility.Epoch;
|
|
||||||
}
|
|
||||||
return symbolPrices.MinDate;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveDate(DateTime date)
|
public void RemoveDate(DateTime date)
|
||||||
{
|
{
|
||||||
lock (thisLock)
|
lock(typeof(LocalPriceCache))
|
||||||
{
|
{
|
||||||
foreach (var kvp in priceCache)
|
List<String> symbols=new List<String>(priceCache.Keys);
|
||||||
|
foreach(String key in symbols)
|
||||||
{
|
{
|
||||||
kvp.Value.Remove(date);
|
PricesByDate pricesByDate=priceCache[key];
|
||||||
|
if(pricesByDate.ContainsKey(date))pricesByDate.Remove(date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public Price GetPrice(String symbol,DateTime date)
|
||||||
public Prices GetPrices(string symbol, DateTime endDate, int dayCount)
|
{
|
||||||
{
|
lock(typeof(LocalPriceCache))
|
||||||
lock (thisLock)
|
|
||||||
{
|
{
|
||||||
if (!priceCache.TryGetValue(symbol, out var pricesByDate)) return new Prices();
|
if(!priceCache.ContainsKey(symbol))return null;
|
||||||
|
PricesByDate pricesByDate=priceCache[symbol];
|
||||||
|
if(!pricesByDate.ContainsKey(date))return null;
|
||||||
|
return pricesByDate[date];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ContainsPrice(String symbol,DateTime date)
|
||||||
|
{
|
||||||
|
lock(typeof(LocalPriceCache))
|
||||||
|
{
|
||||||
|
if(!priceCache.ContainsKey(symbol))return false;
|
||||||
|
PricesByDate pricesByDate=priceCache[symbol];
|
||||||
|
if(!pricesByDate.ContainsKey(date))return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ContainsPrice(List<String> symbols,DateTime date)
|
||||||
|
{
|
||||||
|
lock(typeof(LocalPriceCache))
|
||||||
|
{
|
||||||
|
foreach(String symbol in symbols)if(!ContainsPrice(symbol,date))return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DateGenerator dateGenerator = new DateGenerator();
|
public bool ContainsSymbol(String symbol)
|
||||||
List<DateTime> historicalDates = dateGenerator.GenerateHistoricalDates(endDate, dayCount);
|
{
|
||||||
|
lock(typeof(LocalPriceCache))
|
||||||
Prices result = new Prices();
|
{
|
||||||
foreach (DateTime date in historicalDates)
|
if(priceCache.ContainsKey(symbol))return true;
|
||||||
{
|
return false;
|
||||||
if (pricesByDate.ContainsKey(date))
|
|
||||||
{
|
|
||||||
result.Add(pricesByDate[date]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Price GetPrice(string symbol, DateTime date)
|
public long Count()
|
||||||
{
|
{
|
||||||
lock (thisLock)
|
long count=0;
|
||||||
|
List<String> symbols=priceCache.Keys.ToList();
|
||||||
|
foreach(String symbol in symbols)
|
||||||
{
|
{
|
||||||
if (!priceCache.TryGetValue(symbol, out var pricesByDate)) return null;
|
PricesByDate pricesByDate=priceCache[symbol];
|
||||||
return pricesByDate.TryGetValue(date, out var price) ? price : null;
|
count+=pricesByDate.Count;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ContainsPrice(string symbol, DateTime date)
|
|
||||||
{
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
|
||||||
if (!priceCache.TryGetValue(symbol, out var pricesByDate)) return false;
|
|
||||||
return pricesByDate.ContainsKey(date);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ContainsPrice(List<string> symbols, DateTime date)
|
|
||||||
{
|
|
||||||
if (symbols == null || symbols.Count == 0) return false;
|
|
||||||
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
|
||||||
foreach (string symbol in symbols)
|
|
||||||
{
|
|
||||||
if (!priceCache.TryGetValue(symbol, out var pricesByDate) || !pricesByDate.ContainsKey(date))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ContainsSymbol(string symbol)
|
|
||||||
{
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
|
||||||
return priceCache.ContainsKey(symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private long Count()
|
|
||||||
{
|
|
||||||
lock (thisLock)
|
|
||||||
{
|
|
||||||
long count = 0;
|
|
||||||
foreach (var pricesByDate in priceCache.Values)
|
|
||||||
{
|
|
||||||
count += pricesByDate.Count;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThreadProc()
|
private void ThreadProc()
|
||||||
{
|
{
|
||||||
int quantums = 0;
|
int quantums=0;
|
||||||
int quantumInterval = 1000;
|
int quantumInterval=1000;
|
||||||
long lastCount = 0;
|
long lastCount=0;
|
||||||
|
while(threadRun)
|
||||||
while (threadRun)
|
|
||||||
{
|
{
|
||||||
Thread.Sleep(quantumInterval);
|
Thread.Sleep(quantumInterval);
|
||||||
quantums += quantumInterval;
|
quantums+=quantumInterval;
|
||||||
if (quantums > cacheCycle)
|
if(quantums>cacheCycle)
|
||||||
{
|
{
|
||||||
quantums = 0;
|
quantums=0;
|
||||||
lock (thisLock)
|
lock(thisLock)
|
||||||
{
|
{
|
||||||
lastCount = Count();
|
lastCount=Count();
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG, $"[LocalPriceCache:ThreadProc] Symbols: {priceCache.Keys.Count}. Items in cache: {Utility.FormatNumber(lastCount,0,true)}.");
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("[LocalPriceCache:ThreadProc] Symbols: {0}. Items in cache: {1}.",priceCache.Keys.Count,Utility.FormatNumber(lastCount,0,true)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("[LocalPriceCache:ThreadProc] Thread ended. Items in cache:{0}",Utility.FormatNumber(lastCount,0,true)));
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG, $"[LocalPriceCache:ThreadProc] Thread ended. Items in cache:{Utility.FormatNumber(lastCount,0,true)}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using MarketData.MarketDataModel;
|
|||||||
using MarketData.Utils;
|
using MarketData.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace MarketData.Generator.CMMomentum
|
namespace MarketData.Generator.CMMomentum
|
||||||
@@ -132,6 +133,35 @@ namespace MarketData.Generator.CMMomentum
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// This method is made public in order that it can be tested
|
||||||
|
//public static bool PredictCandidate(CMCandidate cmCandidate,CMParams cmParams)
|
||||||
|
//{
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// CNNClient cnnClient=new CNNClient(cmParams.UseCNNHost);
|
||||||
|
// DataProcessor dataProcessor=new DataProcessor();
|
||||||
|
// dataProcessor.Width=128;
|
||||||
|
// dataProcessor.Height=128;
|
||||||
|
// dataProcessor.PenWidth=1;
|
||||||
|
// TestCase testCase=new TestCase(cmCandidate.Symbol,cmCandidate.TradeDate,cmParams.UseCNNDayCount,TestCase.CaseType.Test,TestCase.GenerateType.BollingerBand,TestCase.OutputType.OutputStream);
|
||||||
|
// dataProcessor.ProcessData(testCase);
|
||||||
|
// String prediction = cnnClient.Predict(CNNClient.Model.resnet50_20241024_270,testCase.LastStream);
|
||||||
|
// prediction=prediction.Substring(prediction.IndexOf("-->"));
|
||||||
|
// int result=int.Parse(Utility.BetweenString(prediction,"[[","]"));
|
||||||
|
// if(1==result)
|
||||||
|
// {
|
||||||
|
// cmCandidate.Score*=(1.00+cmParams.UseCNNRewardPercentDecimal); // increase the score by the percentage indicated in the params settings
|
||||||
|
// cmCandidate.CNNPrediction=true;
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// catch(Exception exception)
|
||||||
|
// {
|
||||||
|
// MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Error encountered calling convolutional model at {0}. Exception was {1}",cmParams.UseCNNHost,exception.ToString()));
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
// This method is made public in order that it can be tested
|
// This method is made public in order that it can be tested
|
||||||
public static bool PredictCandidate(CMCandidate cmCandidate,CMParams cmParams)
|
public static bool PredictCandidate(CMCandidate cmCandidate,CMParams cmParams)
|
||||||
{
|
{
|
||||||
@@ -139,12 +169,14 @@ namespace MarketData.Generator.CMMomentum
|
|||||||
{
|
{
|
||||||
CNNClient cnnClient=new CNNClient(cmParams.UseCNNHost);
|
CNNClient cnnClient=new CNNClient(cmParams.UseCNNHost);
|
||||||
DataProcessor dataProcessor=new DataProcessor();
|
DataProcessor dataProcessor=new DataProcessor();
|
||||||
dataProcessor.Width=128;
|
int imageDimensions=224;
|
||||||
dataProcessor.Height=128;
|
dataProcessor.Width=imageDimensions;
|
||||||
|
dataProcessor.Height=imageDimensions;
|
||||||
dataProcessor.PenWidth=1;
|
dataProcessor.PenWidth=1;
|
||||||
TestCase testCase=new TestCase(cmCandidate.Symbol,cmCandidate.TradeDate,cmParams.UseCNNDayCount,TestCase.CaseType.Test,TestCase.GenerateType.BollingerBand,TestCase.OutputType.OutputStream);
|
TestCase testCase=new TestCase(cmCandidate.Symbol,cmCandidate.TradeDate,cmParams.UseCNNDayCount,TestCase.CaseType.Test,TestCase.GenerateType.BollingerBandWithVIX,TestCase.OutputType.OutputStream);
|
||||||
dataProcessor.ProcessData(testCase);
|
dataProcessor.ProcessData(testCase);
|
||||||
String prediction = cnnClient.Predict(CNNClient.Model.resnet50_20241024_270,testCase.LastStream);
|
Stream streamResult = cnnClient.ProcessImage(testCase.LastStream); // process the image through PIL
|
||||||
|
String prediction = cnnClient.Predict(CNNClient.Model.convnext,streamResult);
|
||||||
prediction=prediction.Substring(prediction.IndexOf("-->"));
|
prediction=prediction.Substring(prediction.IndexOf("-->"));
|
||||||
int result=int.Parse(Utility.BetweenString(prediction,"[[","]"));
|
int result=int.Parse(Utility.BetweenString(prediction,"[[","]"));
|
||||||
if(1==result)
|
if(1==result)
|
||||||
@@ -160,5 +192,7 @@ namespace MarketData.Generator.CMMomentum
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
CMTSESSIONv1.00
|
CMTSESSIONv1.00
|
||||||
LastUpdated=2/23/2026 9:38:02 PM
|
LastUpdated=2/13/2026 8:56:35 PM
|
||||||
TradeDate=2/23/2026
|
TradeDate=2/13/2026
|
||||||
StartDate=1/1/0001
|
StartDate=1/1/0001
|
||||||
AnalysisDate=2/23/2026
|
AnalysisDate=2/13/2026
|
||||||
CashBalance=4287.32
|
CashBalance=4287.32
|
||||||
NonTradeableCash=6456.42
|
NonTradeableCash=6456.42
|
||||||
SuspendTrading=False|UsePriceSlopeIndicator=True|UsePriceSlopeIndicatorDays=252|AnalysisDate=2/23/2026|BetaMonths=6|TradeDate=2/23/2026|MarketCapLowerLimit=500000000|SidewaysDetection=False|SidewaysAfterDays=30|PriceTrendDays=20|CheckOutliersInReturnStream=True|DailyReturnLimit=0.25|MaxDailyPositions=3|MaxOpenPositions=3|NoTradeSymbols=CODYY,MARUY,CSTM,CS,NATI,QADA,CRTO,GTBIF,CLCT,PRSC,CMD,STAY,GBTC,YOKU,PNY,RFMD,ASAZY,USMO,VNR,STB,XIV,SYNT,DFP|OnlyTradeSymbols=|MinRSI=70|InitialCash=10000|TotalRiskPercentDecimal=0.05|PositionRiskPercentDecimal=0.12|EquityOnly=False|MinPercentReturnProximityTo52WeekHigh=30|MinPercentReturnOver52WeekLow=80|ProfitMarginCheck=True|EPSCheck=True|MinDaysBetweenReholding=30|LiquidityCheck=True|MinVolume=1000|DMA200Horizon=15|MinDaysBetweenStopAdjustments=30|MinDaysBetweenInitialStopAdjustment=5|MaxPricingExceptions=3|MACDSetup=(12,26,9)|MACDSignalDays=5|MACDRejectStrongSells=True|MACDRejectWeakSells=True|UseMarketIndicator=True|Benchmark=SPY|BenchmarkMovingAverageDays=200|BenchmarkMovingAverageHorizon=5|UseMarketIndicatorVolatility=True|UseMarketIndicatorVolatilityHorizon=60|UseMarketIndicatorVolatilityBenchmark=^VIX|UseStopLimitScaling=True|StopLimitScalingType=AverageTrueRange|StopLimitScalingVolatilityDays=30|SellOnDMABreak=True|DMABreakValues=200|DMABreakForceBreak=False|EntryType=OverExtended,MVP,PriceTrend,VolumeTrend|EntryHorizon=30|CandidateExpiryDays=180|VolumeTrendDays=10|ChannelBreakoutHorizon=40|UseOverExtendedIndicatorDays=45|UseOverExtendedIndicatorViolationThreshhold=1|UseOverExtendedIndicatorMarginPercent=1|MaxBeta=10|UseMaxBeta=False|UseProfitMaximization=True|UseProfitMaximizationExpression=R_THRESSHOLD=4;MAX_ATR=3;MULTIPLIER=MAX_ATR;IF(RMultiple>=R_THRESSHOLD){MULTIPLIER=1.2;}|UseTradeOnlySectors=False|UseTradeOnlySectorsSectors=Healthcare,Technology,Basic Materials,Consumer Defensive,Industrials|EvaluateStopOnUpTrend=False
|
SuspendTrading=False|UsePriceSlopeIndicator=True|UsePriceSlopeIndicatorDays=252|AnalysisDate=2/13/2026|BetaMonths=6|TradeDate=2/13/2026|MarketCapLowerLimit=500000000|SidewaysDetection=False|SidewaysAfterDays=30|PriceTrendDays=20|CheckOutliersInReturnStream=True|DailyReturnLimit=0.25|MaxDailyPositions=3|MaxOpenPositions=3|NoTradeSymbols=CODYY,MARUY,CSTM,CS,NATI,QADA,CRTO,GTBIF,CLCT,PRSC,CMD,STAY,GBTC,YOKU,PNY,RFMD,ASAZY,USMO,VNR,STB,XIV,SYNT,DFP|OnlyTradeSymbols=|MinRSI=70|InitialCash=10000|TotalRiskPercentDecimal=0.05|PositionRiskPercentDecimal=0.12|EquityOnly=False|MinPercentReturnProximityTo52WeekHigh=30|MinPercentReturnOver52WeekLow=80|ProfitMarginCheck=True|EPSCheck=True|MinDaysBetweenReholding=30|LiquidityCheck=True|MinVolume=1000|DMA200Horizon=15|MinDaysBetweenStopAdjustments=30|MinDaysBetweenInitialStopAdjustment=5|MaxPricingExceptions=3|MACDSetup=(12,26,9)|MACDSignalDays=5|MACDRejectStrongSells=True|MACDRejectWeakSells=True|UseMarketIndicator=True|Benchmark=SPY|BenchmarkMovingAverageDays=200|BenchmarkMovingAverageHorizon=5|UseMarketIndicatorVolatility=True|UseMarketIndicatorVolatilityHorizon=60|UseMarketIndicatorVolatilityBenchmark=^VIX|UseStopLimitScaling=True|StopLimitScalingType=AverageTrueRange|StopLimitScalingVolatilityDays=30|SellOnDMABreak=True|DMABreakValues=200|DMABreakForceBreak=False|EntryType=OverExtended,MVP,PriceTrend,VolumeTrend|EntryHorizon=30|CandidateExpiryDays=180|VolumeTrendDays=10|ChannelBreakoutHorizon=40|UseOverExtendedIndicatorDays=45|UseOverExtendedIndicatorViolationThreshhold=1|UseOverExtendedIndicatorMarginPercent=1|MaxBeta=10|UseMaxBeta=False|UseProfitMaximization=True|UseProfitMaximizationExpression=R_THRESSHOLD=4;MAX_ATR=3;MULTIPLIER=MAX_ATR;IF(RMultiple>=R_THRESSHOLD){MULTIPLIER=1.2;}|UseTradeOnlySectors=False|UseTradeOnlySectorsSectors=Healthcare,Technology,Basic Materials,Consumer Defensive,Industrials|EvaluateStopOnUpTrend=False
|
||||||
PricingExceptions=0
|
PricingExceptions=0
|
||||||
TotalActivePositions=2
|
TotalActivePositions=2
|
||||||
Symbol=HWM|PurchaseDate=11/17/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=11|PurchasePrice=200.81|CurrentPrice=257.04|Exposure=2208.91|MarketValue=2827.44|GainLoss=618.53|GainLossPcnt=0.280015935461382|PositionRiskDecimal=0.12|R=24.0336|C=276.15|P=11.490163770721|InitialStopLimit=176.71|TrailingStopLimit=197.56385799408|TotalRiskExposure=264.3696|RMultiple=2.34R|Volatility=3.68232583999634|Volume=0|LastStopAdjustment=1/26/2026 12:00:00 AM|Comment=Price changed on 11/18/2025 from $200.28 to $200.81
|
Symbol=HWM|PurchaseDate=11/17/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=11|PurchasePrice=200.81|CurrentPrice=250.21|Exposure=2208.91|MarketValue=2752.31|GainLoss=543.4|GainLossPcnt=0.246003685075445|PositionRiskDecimal=0.12|R=24.0336|C=276.15|P=11.490163770721|InitialStopLimit=176.71|TrailingStopLimit=197.56385799408|TotalRiskExposure=264.3696|RMultiple=2.06R|Volatility=3.68232583999634|Volume=0|LastStopAdjustment=1/26/2026 12:00:00 AM|Comment=Price changed on 11/18/2025 from $200.28 to $200.81
|
||||||
Symbol=FTI|PurchaseDate=11/20/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=41|PurchasePrice=43.23|CurrentPrice=64.25|Exposure=1772.43|MarketValue=2634.25|GainLoss=861.82|GainLossPcnt=0.486236409900532|PositionRiskDecimal=0.12|R=5.2188|C=218.4595|P=41.8601019391431|InitialStopLimit=38.04|TrailingStopLimit=50.7683570289612|TotalRiskExposure=213.9708|RMultiple=4.03R|Volatility=0.825829267501831|Volume=0|LastStopAdjustment=1/26/2026 12:00:00 AM|Comment=Price changed on 11/21/2025 from $43.49 to $43.23
|
Symbol=FTI|PurchaseDate=11/20/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=41|PurchasePrice=43.23|CurrentPrice=61.36|Exposure=1772.43|MarketValue=2515.76|GainLoss=743.33|GainLossPcnt=0.419384686560259|PositionRiskDecimal=0.12|R=5.2188|C=218.4595|P=41.8601019391431|InitialStopLimit=38.04|TrailingStopLimit=50.7683570289612|TotalRiskExposure=213.9708|RMultiple=3.47R|Volatility=0.825829267501831|Volume=0|LastStopAdjustment=1/26/2026 12:00:00 AM|Comment=Price changed on 11/21/2025 from $43.49 to $43.23
|
||||||
TotalPositions=133
|
TotalPositions=133
|
||||||
Symbol=CDNS|PurchaseDate=8/25/2020 12:00:00 AM|SellDate=9/3/2020 12:00:00 AM|Shares=16|PurchasePrice=111.82|CurrentPrice=109.57|Exposure=1789.12|MarketValue=1753.12|GainLoss=-36|GainLossPcnt=-0.0201216240386335|PositionRiskDecimal=0.12|R=13.3512|C=225.6365|P=16.9000913775541|InitialStopLimit=97.9088|TrailingStopLimit=109.599856939316|TotalRiskExposure=213.6192|RMultiple=-0.17R|Volatility=2.3209912776947|Volume=1767980|LastStopAdjustment=9/2/2020 12:00:00 AM|Comment=Manual close.
|
Symbol=CDNS|PurchaseDate=8/25/2020 12:00:00 AM|SellDate=9/3/2020 12:00:00 AM|Shares=16|PurchasePrice=111.82|CurrentPrice=109.57|Exposure=1789.12|MarketValue=1753.12|GainLoss=-36|GainLossPcnt=-0.0201216240386335|PositionRiskDecimal=0.12|R=13.3512|C=225.6365|P=16.9000913775541|InitialStopLimit=97.9088|TrailingStopLimit=109.599856939316|TotalRiskExposure=213.6192|RMultiple=-0.17R|Volatility=2.3209912776947|Volume=1767980|LastStopAdjustment=9/2/2020 12:00:00 AM|Comment=Manual close.
|
||||||
Symbol=LULU|PurchaseDate=8/28/2020 12:00:00 AM|SellDate=9/4/2020 12:00:00 AM|Shares=3|PurchasePrice=377.5|CurrentPrice=370.23|Exposure=1132.5|MarketValue=1110.69|GainLoss=-21.8099999999999|GainLossPcnt=-0.0192582781456953|PositionRiskDecimal=0.12|R=45.2976|C=136.6285|P=3.01624147857723|InitialStopLimit=332.1824|TrailingStopLimit=372.562428512573|TotalRiskExposure=135.8928|RMultiple=-0.16R|Volatility=25.858959197998|Volume=2871665|LastStopAdjustment=9/2/2020 12:00:00 AM|Comment=Manual close.
|
Symbol=LULU|PurchaseDate=8/28/2020 12:00:00 AM|SellDate=9/4/2020 12:00:00 AM|Shares=3|PurchasePrice=377.5|CurrentPrice=370.23|Exposure=1132.5|MarketValue=1110.69|GainLoss=-21.8099999999999|GainLossPcnt=-0.0192582781456953|PositionRiskDecimal=0.12|R=45.2976|C=136.6285|P=3.01624147857723|InitialStopLimit=332.1824|TrailingStopLimit=372.562428512573|TotalRiskExposure=135.8928|RMultiple=-0.16R|Volatility=25.858959197998|Volume=2871665|LastStopAdjustment=9/2/2020 12:00:00 AM|Comment=Manual close.
|
||||||
@@ -144,13 +144,14 @@ Symbol=DASH|PurchaseDate=10/20/2025 12:00:00 AM|SellDate=11/6/2025 12:00:00 AM|S
|
|||||||
Symbol=HCI|PurchaseDate=11/6/2025 12:00:00 AM|SellDate=11/17/2025 12:00:00 AM|Shares=12|PurchasePrice=199.2|CurrentPrice=175.62|Exposure=2390.4|MarketValue=2107.44|GainLoss=-282.96|GainLossPcnt=-0.118373493975903|PositionRiskDecimal=0.12|R=23.4012|C=290.298|P=12.4052612686529|InitialStopLimit=175.3|TrailingStopLimit=175.3|TotalRiskExposure=280.8144|RMultiple=-1.01R|Volatility=8.70686626434326|Volume=0|LastStopAdjustment=1/1/0001 12:00:00 AM|Comment=Manual close.
|
Symbol=HCI|PurchaseDate=11/6/2025 12:00:00 AM|SellDate=11/17/2025 12:00:00 AM|Shares=12|PurchasePrice=199.2|CurrentPrice=175.62|Exposure=2390.4|MarketValue=2107.44|GainLoss=-282.96|GainLossPcnt=-0.118373493975903|PositionRiskDecimal=0.12|R=23.4012|C=290.298|P=12.4052612686529|InitialStopLimit=175.3|TrailingStopLimit=175.3|TotalRiskExposure=280.8144|RMultiple=-1.01R|Volatility=8.70686626434326|Volume=0|LastStopAdjustment=1/1/0001 12:00:00 AM|Comment=Manual close.
|
||||||
Symbol=NFLX|PurchaseDate=10/21/2025 12:00:00 AM|SellDate=11/20/2025 12:00:00 AM|Shares=10|PurchasePrice=114.35|CurrentPrice=105.51|Exposure=1143.5|MarketValue=1055.1|GainLoss=-88.3999999999999|GainLossPcnt=-0.0773065150852644|PositionRiskDecimal=0.12|R=148.962|C=201.1665|P=1.35045514963548|InitialStopLimit=100.62|TrailingStopLimit=105.51|TotalRiskExposure=1489.62|RMultiple=-0.06R|Volatility=19.877721786499|Volume=0|LastStopAdjustment=11/13/2025 12:00:00 AM|Comment=Manual close.
|
Symbol=NFLX|PurchaseDate=10/21/2025 12:00:00 AM|SellDate=11/20/2025 12:00:00 AM|Shares=10|PurchasePrice=114.35|CurrentPrice=105.51|Exposure=1143.5|MarketValue=1055.1|GainLoss=-88.3999999999999|GainLossPcnt=-0.0773065150852644|PositionRiskDecimal=0.12|R=148.962|C=201.1665|P=1.35045514963548|InitialStopLimit=100.62|TrailingStopLimit=105.51|TotalRiskExposure=1489.62|RMultiple=-0.06R|Volatility=19.877721786499|Volume=0|LastStopAdjustment=11/13/2025 12:00:00 AM|Comment=Manual close.
|
||||||
Symbol=CX|PurchaseDate=10/20/2025 12:00:00 AM|SellDate=2/5/2026 12:00:00 AM|Shares=144|PurchasePrice=9.54|CurrentPrice=11.74|Exposure=1373.76|MarketValue=1690.56|GainLoss=316.8|GainLossPcnt=0.230607966457023|PositionRiskDecimal=0.12|R=1.1472|C=166.144|P=144.825662482566|InitialStopLimit=8.4|TrailingStopLimit=12.0339285671711|TotalRiskExposure=165.1968|RMultiple=1.92R|Volatility=0.164089068770409|Volume=0|LastStopAdjustment=1/28/2026 12:00:00 AM|Comment=Manual close.
|
Symbol=CX|PurchaseDate=10/20/2025 12:00:00 AM|SellDate=2/5/2026 12:00:00 AM|Shares=144|PurchasePrice=9.54|CurrentPrice=11.74|Exposure=1373.76|MarketValue=1690.56|GainLoss=316.8|GainLossPcnt=0.230607966457023|PositionRiskDecimal=0.12|R=1.1472|C=166.144|P=144.825662482566|InitialStopLimit=8.4|TrailingStopLimit=12.0339285671711|TotalRiskExposure=165.1968|RMultiple=1.92R|Volatility=0.164089068770409|Volume=0|LastStopAdjustment=1/28/2026 12:00:00 AM|Comment=Manual close.
|
||||||
TotalCandidates=128
|
TotalCandidates=120
|
||||||
Symbol=FINMY|AnalysisDate=10/2/2025 12:00:00 AM|EPSSlope=0.0349999964237213|ProfitMarginSlope=2.26086616516113|PriceSlope=0.00448679936177329|Volatility=1.03268754482269|Volume=0|Violation=False|Slope=0.00448679936177329|Score=2.66255318366838|AnnualizedReturn=3.09774193858814|SharpeRatio=0.335718769738377|RSquared=0.859514199843871|BetaMonths=6|Beta=0.824935419784389
|
Symbol=FINMY|AnalysisDate=10/2/2025 12:00:00 AM|EPSSlope=0.0349999964237213|ProfitMarginSlope=2.26086616516113|PriceSlope=0.00448679936177329|Volatility=1.03268754482269|Volume=0|Violation=False|Slope=0.00448679936177329|Score=2.66255318366838|AnnualizedReturn=3.09774193858814|SharpeRatio=0.335718769738377|RSquared=0.859514199843871|BetaMonths=6|Beta=0.824935419784389
|
||||||
Symbol=RYCEY|AnalysisDate=10/1/2025 12:00:00 AM|EPSSlope=0.0249999910593033|ProfitMarginSlope=2.86403560638428|PriceSlope=0.00377742185948191|Volatility=0.317665636539459|Volume=0|Violation=False|Slope=0.00377742185948191|Score=2.3960549250413|AnnualizedReturn=2.59065388368147|SharpeRatio=0.325355777751677|RSquared=0.924884231017524|BetaMonths=6|Beta=1.39611806037306
|
Symbol=RYCEY|AnalysisDate=10/1/2025 12:00:00 AM|EPSSlope=0.0249999910593033|ProfitMarginSlope=2.86403560638428|PriceSlope=0.00377742185948191|Volatility=0.317665636539459|Volume=0|Violation=False|Slope=0.00377742185948191|Score=2.3960549250413|AnnualizedReturn=2.59065388368147|SharpeRatio=0.325355777751677|RSquared=0.924884231017524|BetaMonths=6|Beta=1.39611806037306
|
||||||
Symbol=TTMI|AnalysisDate=9/23/2025 12:00:00 AM|EPSSlope=0.0699999928474426|ProfitMarginSlope=0.416337013244629|PriceSlope=0.00365635399457596|Volatility=3.10769009590149|Volume=0|Violation=False|Slope=0.00365635399457596|Score=1.73840687121807|AnnualizedReturn=2.5128088887714|SharpeRatio=0.319624993971795|RSquared=0.691818179642002|BetaMonths=6|Beta=4.40428456309766
|
Symbol=TTMI|AnalysisDate=9/23/2025 12:00:00 AM|EPSSlope=0.0699999928474426|ProfitMarginSlope=0.416337013244629|PriceSlope=0.00365635399457596|Volatility=3.10769009590149|Volume=0|Violation=False|Slope=0.00365635399457596|Score=1.73840687121807|AnnualizedReturn=2.5128088887714|SharpeRatio=0.319624993971795|RSquared=0.691818179642002|BetaMonths=6|Beta=4.40428456309766
|
||||||
Symbol=SBSW|AnalysisDate=9/25/2025 12:00:00 AM|EPSSlope=0.144999995827675|ProfitMarginSlope=8.49569129943848|PriceSlope=0.00379709174022612|Volatility=0.753211140632629|Volume=0|Violation=False|Slope=0.00379709174022612|Score=1.72251869189193|AnnualizedReturn=2.60352714141071|SharpeRatio=0.241739220317797|RSquared=0.661609654262558|BetaMonths=6|Beta=1.87093907966492
|
Symbol=SBSW|AnalysisDate=9/25/2025 12:00:00 AM|EPSSlope=0.144999995827675|ProfitMarginSlope=8.49569129943848|PriceSlope=0.00379709174022612|Volatility=0.753211140632629|Volume=0|Violation=False|Slope=0.00379709174022612|Score=1.72251869189193|AnnualizedReturn=2.60352714141071|SharpeRatio=0.241739220317797|RSquared=0.661609654262558|BetaMonths=6|Beta=1.87093907966492
|
||||||
Symbol=NTES|AnalysisDate=9/15/2025 12:00:00 AM|EPSSlope=0.204999923706055|ProfitMarginSlope=1.94379615783691|PriceSlope=0.00231223761471691|Volatility=7.26750755310059|Volume=0|Violation=False|Slope=0.00231223761471691|Score=1.55371831188788|AnnualizedReturn=1.79083837998442|SharpeRatio=0.0978165524611287|RSquared=0.867592703648334|BetaMonths=6|Beta=1.22658293677365
|
Symbol=NTES|AnalysisDate=9/15/2025 12:00:00 AM|EPSSlope=0.204999923706055|ProfitMarginSlope=1.94379615783691|PriceSlope=0.00231223761471691|Volatility=7.26750755310059|Volume=0|Violation=False|Slope=0.00231223761471691|Score=1.55371831188788|AnnualizedReturn=1.79083837998442|SharpeRatio=0.0978165524611287|RSquared=0.867592703648334|BetaMonths=6|Beta=1.22658293677365
|
||||||
Symbol=SANM|AnalysisDate=10/6/2025 12:00:00 AM|EPSSlope=0.174999952316284|ProfitMarginSlope=0.24951171875|PriceSlope=0.00208239218708193|Volatility=6.52257966995239|Volume=0|Violation=False|Slope=0.00208239218708193|Score=1.2404476041886|AnnualizedReturn=1.6900579717286|SharpeRatio=0.133157857131703|RSquared=0.733967488061884|BetaMonths=6|Beta=1.12080932540038
|
Symbol=SANM|AnalysisDate=10/6/2025 12:00:00 AM|EPSSlope=0.174999952316284|ProfitMarginSlope=0.24951171875|PriceSlope=0.00208239218708193|Volatility=6.52257966995239|Volume=0|Violation=False|Slope=0.00208239218708193|Score=1.2404476041886|AnnualizedReturn=1.6900579717286|SharpeRatio=0.133157857131703|RSquared=0.733967488061884|BetaMonths=6|Beta=1.12080932540038
|
||||||
|
Symbol=VSEC|AnalysisDate=8/18/2025 12:00:00 AM|EPSSlope=0.479999989271164|ProfitMarginSlope=0.627522468566895|PriceSlope=0.00197968074908862|Volatility=7.79957246780396|Volume=0|Violation=False|Slope=0.00197968074908862|Score=1.23555493984458|AnnualizedReturn=1.64687499344999|SharpeRatio=0.0848111495425649|RSquared=0.750242091694071|BetaMonths=6|Beta=0.00511743208922735
|
||||||
Symbol=APH|AnalysisDate=9/10/2025 12:00:00 AM|EPSSlope=0.225000023841858|ProfitMarginSlope=1.02336883544922|PriceSlope=0.00218577417499694|Volatility=3.01760697364807|Volume=0|Violation=False|Slope=0.00218577417499694|Score=1.19871329173408|AnnualizedReturn=1.73466635462984|SharpeRatio=0.117857316723347|RSquared=0.691033920462406|BetaMonths=6|Beta=1.29660077545655
|
Symbol=APH|AnalysisDate=9/10/2025 12:00:00 AM|EPSSlope=0.225000023841858|ProfitMarginSlope=1.02336883544922|PriceSlope=0.00218577417499694|Volatility=3.01760697364807|Volume=0|Violation=False|Slope=0.00218577417499694|Score=1.19871329173408|AnnualizedReturn=1.73466635462984|SharpeRatio=0.117857316723347|RSquared=0.691033920462406|BetaMonths=6|Beta=1.29660077545655
|
||||||
Symbol=BVN|AnalysisDate=9/22/2025 12:00:00 AM|EPSSlope=0.0400000214576721|ProfitMarginSlope=3.35278701782227|PriceSlope=0.00178832525596272|Volatility=0.509544312953949|Volume=0|Violation=False|Slope=0.00178832525596272|Score=1.1871859154563|AnnualizedReturn=1.56934441878645|SharpeRatio=0.0627467548412755|RSquared=0.756485256674465|BetaMonths=6|Beta=0.0852063395469229
|
Symbol=BVN|AnalysisDate=9/22/2025 12:00:00 AM|EPSSlope=0.0400000214576721|ProfitMarginSlope=3.35278701782227|PriceSlope=0.00178832525596272|Volatility=0.509544312953949|Volume=0|Violation=False|Slope=0.00178832525596272|Score=1.1871859154563|AnnualizedReturn=1.56934441878645|SharpeRatio=0.0627467548412755|RSquared=0.756485256674465|BetaMonths=6|Beta=0.0852063395469229
|
||||||
Symbol=FN|AnalysisDate=11/4/2025 12:00:00 AM|EPSSlope=0.0999999046325684|ProfitMarginSlope=0.0680141448974609|PriceSlope=0.00254868146461796|Volatility=18.239673614502|Volume=0|Violation=False|Slope=0.00254868146461796|Score=1.12395010145193|AnnualizedReturn=1.90078646425663|SharpeRatio=0.156706951792266|RSquared=0.591307925738777|BetaMonths=6|Beta=1.07114601199124
|
Symbol=FN|AnalysisDate=11/4/2025 12:00:00 AM|EPSSlope=0.0999999046325684|ProfitMarginSlope=0.0680141448974609|PriceSlope=0.00254868146461796|Volatility=18.239673614502|Volume=0|Violation=False|Slope=0.00254868146461796|Score=1.12395010145193|AnnualizedReturn=1.90078646425663|SharpeRatio=0.156706951792266|RSquared=0.591307925738777|BetaMonths=6|Beta=1.07114601199124
|
||||||
@@ -171,6 +172,7 @@ Symbol=GLW|AnalysisDate=9/5/2025 12:00:00 AM|EPSSlope=0.21000000834465|ProfitMar
|
|||||||
Symbol=BWXT|AnalysisDate=10/1/2025 12:00:00 AM|EPSSlope=0.0299999713897705|ProfitMarginSlope=0.842325210571289|PriceSlope=0.00148142098327814|Volatility=5.46874237060547|Volume=0|Violation=False|Slope=0.00148142098327814|Score=0.535519927511107|AnnualizedReturn=1.45254630359425|SharpeRatio=0.0847391180072971|RSquared=0.368676665374447|BetaMonths=6|Beta=1.20408002256826
|
Symbol=BWXT|AnalysisDate=10/1/2025 12:00:00 AM|EPSSlope=0.0299999713897705|ProfitMarginSlope=0.842325210571289|PriceSlope=0.00148142098327814|Volatility=5.46874237060547|Volume=0|Violation=False|Slope=0.00148142098327814|Score=0.535519927511107|AnnualizedReturn=1.45254630359425|SharpeRatio=0.0847391180072971|RSquared=0.368676665374447|BetaMonths=6|Beta=1.20408002256826
|
||||||
Symbol=MU|AnalysisDate=10/16/2025 12:00:00 AM|EPSSlope=1.01999998092651|ProfitMarginSlope=3.93631362915039|PriceSlope=0.0017836395604108|Volatility=12.5083780288696|Volume=0|Violation=False|Slope=0.0017836395604108|Score=0.535470880696113|AnnualizedReturn=1.56749243792573|SharpeRatio=0.131165993959009|RSquared=0.341609865374982|BetaMonths=6|Beta=3.80362957802949
|
Symbol=MU|AnalysisDate=10/16/2025 12:00:00 AM|EPSSlope=1.01999998092651|ProfitMarginSlope=3.93631362915039|PriceSlope=0.0017836395604108|Volatility=12.5083780288696|Volume=0|Violation=False|Slope=0.0017836395604108|Score=0.535470880696113|AnnualizedReturn=1.56749243792573|SharpeRatio=0.131165993959009|RSquared=0.341609865374982|BetaMonths=6|Beta=3.80362957802949
|
||||||
Symbol=COLL|AnalysisDate=11/17/2025 12:00:00 AM|EPSSlope=0.285000026226044|ProfitMarginSlope=3.47329521179199|PriceSlope=0.000996351284585738|Volatility=4.86669015884399|Volume=0|Violation=False|Slope=0.000996351284585738|Score=0.498972314260969|AnnualizedReturn=1.28541358644203|SharpeRatio=-0.244881207463219|RSquared=0.388180364299792|BetaMonths=6|Beta=1.46108876190814
|
Symbol=COLL|AnalysisDate=11/17/2025 12:00:00 AM|EPSSlope=0.285000026226044|ProfitMarginSlope=3.47329521179199|PriceSlope=0.000996351284585738|Volatility=4.86669015884399|Volume=0|Violation=False|Slope=0.000996351284585738|Score=0.498972314260969|AnnualizedReturn=1.28541358644203|SharpeRatio=-0.244881207463219|RSquared=0.388180364299792|BetaMonths=6|Beta=1.46108876190814
|
||||||
|
Symbol=BELFB|AnalysisDate=8/25/2025 12:00:00 AM|EPSSlope=0.285000085830688|ProfitMarginSlope=0.582233428955078|PriceSlope=0.00141653955297341|Volatility=2.603111743927|Volume=0|Violation=False|Slope=0.00141653955297341|Score=0.480716598993722|AnnualizedReturn=1.4289900947802|SharpeRatio=0.119774159326474|RSquared=0.336403030888512|BetaMonths=6|Beta=2.43681291066381
|
||||||
Symbol=GSL|AnalysisDate=9/18/2025 12:00:00 AM|EPSSlope=0.0900001525878906|ProfitMarginSlope=0.176097869873047|PriceSlope=0.00102036281428555|Volatility=0.917586147785187|Volume=0|Violation=False|Slope=0.00102036281428555|Score=0.447266351637514|AnnualizedReturn=1.29321508181417|SharpeRatio=-0.240771308468293|RSquared=0.345856120862797|BetaMonths=6|Beta=0.967212765650389
|
Symbol=GSL|AnalysisDate=9/18/2025 12:00:00 AM|EPSSlope=0.0900001525878906|ProfitMarginSlope=0.176097869873047|PriceSlope=0.00102036281428555|Volatility=0.917586147785187|Volume=0|Violation=False|Slope=0.00102036281428555|Score=0.447266351637514|AnnualizedReturn=1.29321508181417|SharpeRatio=-0.240771308468293|RSquared=0.345856120862797|BetaMonths=6|Beta=0.967212765650389
|
||||||
Symbol=CGAU|AnalysisDate=9/25/2025 12:00:00 AM|EPSSlope=0.0750000029802322|ProfitMarginSlope=7.88293075561523|PriceSlope=0.0009970382360156|Volatility=0.387202262878418|Volume=0|Violation=False|Slope=0.0009970382360156|Score=0.429807798377358|AnnualizedReturn=1.28563612591224|SharpeRatio=-0.153030522888472|RSquared=0.334315277639216|BetaMonths=6|Beta=0.89521003942289
|
Symbol=CGAU|AnalysisDate=9/25/2025 12:00:00 AM|EPSSlope=0.0750000029802322|ProfitMarginSlope=7.88293075561523|PriceSlope=0.0009970382360156|Volatility=0.387202262878418|Volume=0|Violation=False|Slope=0.0009970382360156|Score=0.429807798377358|AnnualizedReturn=1.28563612591224|SharpeRatio=-0.153030522888472|RSquared=0.334315277639216|BetaMonths=6|Beta=0.89521003942289
|
||||||
Symbol=MD|AnalysisDate=11/17/2025 12:00:00 AM|EPSSlope=0.300000011920929|ProfitMarginSlope=3.04110622406006|PriceSlope=0.000999694216261977|Volatility=2.24461984634399|Volume=0|Violation=False|Slope=0.000999694216261977|Score=0.412248257927109|AnnualizedReturn=1.28649689922789|SharpeRatio=-0.0107905850378413|RSquared=0.320442480797681|BetaMonths=6|Beta=3.52283407368269
|
Symbol=MD|AnalysisDate=11/17/2025 12:00:00 AM|EPSSlope=0.300000011920929|ProfitMarginSlope=3.04110622406006|PriceSlope=0.000999694216261977|Volatility=2.24461984634399|Volume=0|Violation=False|Slope=0.000999694216261977|Score=0.412248257927109|AnnualizedReturn=1.28649689922789|SharpeRatio=-0.0107905850378413|RSquared=0.320442480797681|BetaMonths=6|Beta=3.52283407368269
|
||||||
@@ -182,6 +184,7 @@ Symbol=LVS|AnalysisDate=11/20/2025 12:00:00 AM|EPSSlope=0.120000004768372|Profit
|
|||||||
Symbol=HBM|AnalysisDate=9/3/2025 12:00:00 AM|EPSSlope=0.175000011920929|ProfitMarginSlope=0.490240097045898|PriceSlope=0.000729030817168273|Volatility=0.487358808517456|Volume=0|Violation=False|Slope=0.000729030817168273|Score=0.175331906747473|AnnualizedReturn=1.20167421779262|SharpeRatio=0.0685094425688964|RSquared=0.145906356441219|BetaMonths=6|Beta=2.69015248129092
|
Symbol=HBM|AnalysisDate=9/3/2025 12:00:00 AM|EPSSlope=0.175000011920929|ProfitMarginSlope=0.490240097045898|PriceSlope=0.000729030817168273|Volatility=0.487358808517456|Volume=0|Violation=False|Slope=0.000729030817168273|Score=0.175331906747473|AnnualizedReturn=1.20167421779262|SharpeRatio=0.0685094425688964|RSquared=0.145906356441219|BetaMonths=6|Beta=2.69015248129092
|
||||||
Symbol=BILI|AnalysisDate=9/15/2025 12:00:00 AM|EPSSlope=0.135000005364418|ProfitMarginSlope=1.50113868713379|PriceSlope=0.000573695565703754|Volatility=1.41854751110077|Volume=0|Violation=False|Slope=0.000573695565703754|Score=0.108280835698724|AnnualizedReturn=1.1555440621639|SharpeRatio=0.067556996898538|RSquared=0.0937055013687271|BetaMonths=6|Beta=0.725243490158731
|
Symbol=BILI|AnalysisDate=9/15/2025 12:00:00 AM|EPSSlope=0.135000005364418|ProfitMarginSlope=1.50113868713379|PriceSlope=0.000573695565703754|Volatility=1.41854751110077|Volume=0|Violation=False|Slope=0.000573695565703754|Score=0.108280835698724|AnnualizedReturn=1.1555440621639|SharpeRatio=0.067556996898538|RSquared=0.0937055013687271|BetaMonths=6|Beta=0.725243490158731
|
||||||
Symbol=MCY|AnalysisDate=10/3/2025 12:00:00 AM|EPSSlope=0.934999942779541|ProfitMarginSlope=2.7081880569458|PriceSlope=0.000598694193818475|Volatility=2.73796057701111|Volume=0|Violation=False|Slope=0.000598694193818475|Score=0.0983982079050049|AnnualizedReturn=1.16284656774647|SharpeRatio=-0.0693450586498807|RSquared=0.0846183930315889|BetaMonths=6|Beta=1.50736316396258
|
Symbol=MCY|AnalysisDate=10/3/2025 12:00:00 AM|EPSSlope=0.934999942779541|ProfitMarginSlope=2.7081880569458|PriceSlope=0.000598694193818475|Volatility=2.73796057701111|Volume=0|Violation=False|Slope=0.000598694193818475|Score=0.0983982079050049|AnnualizedReturn=1.16284656774647|SharpeRatio=-0.0693450586498807|RSquared=0.0846183930315889|BetaMonths=6|Beta=1.50736316396258
|
||||||
|
Symbol=VITL|AnalysisDate=8/22/2025 12:00:00 AM|EPSSlope=0.00499999523162842|ProfitMarginSlope=1.38887023925781|PriceSlope=0.000455363083461419|Volatility=4.98714113235474|Volume=0|Violation=False|Slope=0.000455363083461419|Score=0.083100854866897|AnnualizedReturn=1.12159468333037|SharpeRatio=-0.244814541455398|RSquared=0.0740916982774419|BetaMonths=6|Beta=1.21500191244139
|
||||||
Symbol=CSIQ|AnalysisDate=10/31/2025 12:00:00 AM|EPSSlope=0.0249999985098839|ProfitMarginSlope=7.77392435073853|PriceSlope=0.000623090718563301|Volatility=1.79284286499023|Volume=0|Violation=False|Slope=0.000623090718563301|Score=0.0807088026857748|AnnualizedReturn=1.1700176814875|SharpeRatio=-0.187760717880484|RSquared=0.0689808401725739|BetaMonths=6|Beta=1.33520035507038
|
Symbol=CSIQ|AnalysisDate=10/31/2025 12:00:00 AM|EPSSlope=0.0249999985098839|ProfitMarginSlope=7.77392435073853|PriceSlope=0.000623090718563301|Volatility=1.79284286499023|Volume=0|Violation=False|Slope=0.000623090718563301|Score=0.0807088026857748|AnnualizedReturn=1.1700176814875|SharpeRatio=-0.187760717880484|RSquared=0.0689808401725739|BetaMonths=6|Beta=1.33520035507038
|
||||||
Symbol=MUX|AnalysisDate=9/2/2025 12:00:00 AM|EPSSlope=0.155000001192093|ProfitMarginSlope=12.6074028015137|PriceSlope=0.000420282872695496|Volatility=0.892517030239105|Volume=0|Violation=False|Slope=0.000420282872695496|Score=0.0505830547931327|AnnualizedReturn=1.11172324440238|SharpeRatio=0.0664507478013526|RSquared=0.0454996826303873|BetaMonths=6|Beta=2.4677990769044
|
Symbol=MUX|AnalysisDate=9/2/2025 12:00:00 AM|EPSSlope=0.155000001192093|ProfitMarginSlope=12.6074028015137|PriceSlope=0.000420282872695496|Volatility=0.892517030239105|Volume=0|Violation=False|Slope=0.000420282872695496|Score=0.0505830547931327|AnnualizedReturn=1.11172324440238|SharpeRatio=0.0664507478013526|RSquared=0.0454996826303873|BetaMonths=6|Beta=2.4677990769044
|
||||||
Symbol=TV|AnalysisDate=9/5/2025 12:00:00 AM|EPSSlope=0.0250000059604645|ProfitMarginSlope=3.05452346801758|PriceSlope=0.000362561864863969|Volatility=0.196487531065941|Volume=0|Violation=False|Slope=0.000362561864863969|Score=0.0409861983117743|AnnualizedReturn=1.09566949779821|SharpeRatio=0.0530850799580673|RSquared=0.0374074466745106|BetaMonths=6|Beta=2.16132791096815
|
Symbol=TV|AnalysisDate=9/5/2025 12:00:00 AM|EPSSlope=0.0250000059604645|ProfitMarginSlope=3.05452346801758|PriceSlope=0.000362561864863969|Volatility=0.196487531065941|Volume=0|Violation=False|Slope=0.000362561864863969|Score=0.0409861983117743|AnnualizedReturn=1.09566949779821|SharpeRatio=0.0530850799580673|RSquared=0.0374074466745106|BetaMonths=6|Beta=2.16132791096815
|
||||||
@@ -262,17 +265,6 @@ Symbol=PSMT|AnalysisDate=2/4/2026 12:00:00 AM|EPSSlope=0.0399999618530273|Profit
|
|||||||
Symbol=DCI|AnalysisDate=2/4/2026 12:00:00 AM|EPSSlope=0.0800000429153442|ProfitMarginSlope=0.454849243164063|PriceSlope=0.00170455784568539|Volatility=1.97363579273224|Volume=0|Violation=False|Slope=0.00170455784568539|Score=1.31671434176791|AnnualizedReturn=1.53656372692812|SharpeRatio=-0.0863957755266661|RSquared=0.856921401106001|BetaMonths=6|Beta=0.807390077629777
|
Symbol=DCI|AnalysisDate=2/4/2026 12:00:00 AM|EPSSlope=0.0800000429153442|ProfitMarginSlope=0.454849243164063|PriceSlope=0.00170455784568539|Volatility=1.97363579273224|Volume=0|Violation=False|Slope=0.00170455784568539|Score=1.31671434176791|AnnualizedReturn=1.53656372692812|SharpeRatio=-0.0863957755266661|RSquared=0.856921401106001|BetaMonths=6|Beta=0.807390077629777
|
||||||
Symbol=VIV|AnalysisDate=2/5/2026 12:00:00 AM|EPSSlope=0.0150000154972076|ProfitMarginSlope=0.774349212646484|PriceSlope=0.0018972653337033|Volatility=0.896089375019073|Volume=0|Violation=False|Slope=0.0018972653337033|Score=1.34104616717728|AnnualizedReturn=1.61302429994768|SharpeRatio=0.0802914461607737|RSquared=0.831386214839278|BetaMonths=6|Beta=0.658849608391599
|
Symbol=VIV|AnalysisDate=2/5/2026 12:00:00 AM|EPSSlope=0.0150000154972076|ProfitMarginSlope=0.774349212646484|PriceSlope=0.0018972653337033|Volatility=0.896089375019073|Volume=0|Violation=False|Slope=0.0018972653337033|Score=1.34104616717728|AnnualizedReturn=1.61302429994768|SharpeRatio=0.0802914461607737|RSquared=0.831386214839278|BetaMonths=6|Beta=0.658849608391599
|
||||||
Symbol=ACA|AnalysisDate=2/10/2026 12:00:00 AM|EPSSlope=0.569999992847443|ProfitMarginSlope=2.10593795776367|PriceSlope=0.00135427268924872|Volatility=4.8927788734436|Volume=0|Violation=False|Slope=0.00135427268924872|Score=0.959654963471782|AnnualizedReturn=1.40674245753235|SharpeRatio=-0.232548548203499|RSquared=0.682182412518612|BetaMonths=6|Beta=0.558306829669136
|
Symbol=ACA|AnalysisDate=2/10/2026 12:00:00 AM|EPSSlope=0.569999992847443|ProfitMarginSlope=2.10593795776367|PriceSlope=0.00135427268924872|Volatility=4.8927788734436|Volume=0|Violation=False|Slope=0.00135427268924872|Score=0.959654963471782|AnnualizedReturn=1.40674245753235|SharpeRatio=-0.232548548203499|RSquared=0.682182412518612|BetaMonths=6|Beta=0.558306829669136
|
||||||
Symbol=SPHR|AnalysisDate=2/17/2026 12:00:00 AM|EPSSlope=1.34500002861023|ProfitMarginSlope=2.51224708557129|PriceSlope=0.00523907012952609|Volatility=8.95045948028564|Volume=0|Violation=False|Slope=0.00523907012952609|Score=3.20870287565322|AnnualizedReturn=3.74434114645189|SharpeRatio=0.218491066644505|RSquared=0.856947257248118|BetaMonths=6|Beta=3.21248816680421
|
|
||||||
Symbol=AEIS|AnalysisDate=2/17/2026 12:00:00 AM|EPSSlope=0.00999999046325684|ProfitMarginSlope=0.814477920532227|PriceSlope=0.00426370997524409|Volatility=22.9871597290039|Volume=0|Violation=False|Slope=0.00426370997524409|Score=2.66714040431645|AnnualizedReturn=2.92839623692391|SharpeRatio=0.421589812378226|RSquared=0.910785354347438|BetaMonths=6|Beta=3.7968120892911
|
|
||||||
Symbol=VRT|AnalysisDate=2/17/2026 12:00:00 AM|EPSSlope=0.379999995231628|ProfitMarginSlope=2.02690315246582|PriceSlope=0.00388394295179174|Volatility=23.7274208068848|Volume=0|Violation=False|Slope=0.00388394295179174|Score=2.25005270680435|AnnualizedReturn=2.66113739591567|SharpeRatio=0.122049768039598|RSquared=0.845522937018489|BetaMonths=6|Beta=4.55406437863137
|
|
||||||
Symbol=PAHC|AnalysisDate=2/17/2026 12:00:00 AM|EPSSlope=0.300000011920929|ProfitMarginSlope=3.21435642242432|PriceSlope=0.00374364997253655|Volatility=5.95380306243896|Volume=0|Violation=False|Slope=0.00374364997253655|Score=2.12819854519029|AnnualizedReturn=2.56869963711064|SharpeRatio=0.184901261217851|RSquared=0.828512027815039|BetaMonths=6|Beta=6.70791192761971
|
|
||||||
Symbol=BWA|AnalysisDate=2/17/2026 12:00:00 AM|EPSSlope=0.295000016689301|ProfitMarginSlope=1.43632125854492|PriceSlope=0.00264878087635921|Volatility=6.97055912017822|Volume=0|Violation=False|Slope=0.00264878087635921|Score=1.73266971161757|AnnualizedReturn=1.94934375656964|SharpeRatio=0.0294760197755666|RSquared=0.888847698502722|BetaMonths=6|Beta=0.749787397929552
|
|
||||||
Symbol=HWM|AnalysisDate=2/17/2026 12:00:00 AM|EPSSlope=0.0750000476837158|ProfitMarginSlope=0.679458618164063|PriceSlope=0.00226567934237701|Volatility=15.8062677383423|Volume=0|Violation=False|Slope=0.00226567934237701|Score=1.49471479981506|AnnualizedReturn=1.76994981712852|SharpeRatio=0.104874604929631|RSquared=0.844495581371914|BetaMonths=6|Beta=1.4716901369434
|
|
||||||
Symbol=TIMB|AnalysisDate=2/17/2026 12:00:00 AM|EPSSlope=0.0699999928474426|ProfitMarginSlope=1.20602607727051|PriceSlope=0.00199482432587108|Volatility=1.30688989162445|Volume=0|Violation=False|Slope=0.00199482432587108|Score=1.36503022074127|AnnualizedReturn=1.65317177427138|SharpeRatio=0.147781257421024|RSquared=0.825703802826477|BetaMonths=6|Beta=3.19165382029475
|
|
||||||
Symbol=MSGE|AnalysisDate=2/18/2026 12:00:00 AM|EPSSlope=0.190000027418137|ProfitMarginSlope=9.9661922454834|PriceSlope=0.00257838089510811|Volatility=1.4681134223938|Volume=0|Violation=False|Slope=0.00257838089510811|Score=1.72098906390133|AnnualizedReturn=1.91506580615047|SharpeRatio=0.138978808993797|RSquared=0.898657925160674|BetaMonths=6|Beta=1.34875445513012
|
|
||||||
Symbol=CRUS|AnalysisDate=2/18/2026 12:00:00 AM|EPSSlope=0.275000095367432|ProfitMarginSlope=0.257987976074219|PriceSlope=0.00138302434593785|Volatility=6.7416615486145|Volume=0|Violation=False|Slope=0.00138302434593785|Score=0.99276144864185|AnnualizedReturn=1.41697190749937|SharpeRatio=-0.160325230400514|RSquared=0.700621828412847|BetaMonths=6|Beta=4.37158193573655
|
|
||||||
Symbol=KN|AnalysisDate=2/20/2026 12:00:00 AM|EPSSlope=0.0450000166893005|ProfitMarginSlope=1.58130264282227|PriceSlope=0.0022407357950537|Volatility=1.25567162036896|Volume=0|Violation=False|Slope=0.0022407357950537|Score=1.48837295417815|AnnualizedReturn=1.75885920577315|SharpeRatio=-0.0777997706291159|RSquared=0.846214949606441|BetaMonths=6|Beta=2.73446817127298
|
|
||||||
Symbol=DHT|AnalysisDate=2/20/2026 12:00:00 AM|EPSSlope=0.0349999666213989|ProfitMarginSlope=7.21533393859863|PriceSlope=0.00126847140872784|Volatility=1.08960521221161|Volume=0|Violation=False|Slope=0.00126847140872784|Score=1.02759147711618|AnnualizedReturn=1.37665245498958|SharpeRatio=-0.164685534611809|RSquared=0.746442192720277|BetaMonths=6|Beta=1.44097492371681
|
|
||||||
TotalStopLimits=211
|
TotalStopLimits=211
|
||||||
Symbol=CDNS|AnalysisDate=9/2/2020 12:00:00 AM|PreviousStop=97.9088|NewStop=109.599856939316|CurrentPriceLow=113.59|CurrentPriceClose=117.09|PriceTrendIndicatorSlope=0.310654103755951|StopLimitId=
|
Symbol=CDNS|AnalysisDate=9/2/2020 12:00:00 AM|PreviousStop=97.9088|NewStop=109.599856939316|CurrentPriceLow=113.59|CurrentPriceClose=117.09|PriceTrendIndicatorSlope=0.310654103755951|StopLimitId=
|
||||||
Symbol=LULU|AnalysisDate=9/2/2020 12:00:00 AM|PreviousStop=332.1824|NewStop=372.562428512573|CurrentPriceLow=387.08|CurrentPriceClose=398.29|PriceTrendIndicatorSlope=2.77707505226135|StopLimitId=
|
Symbol=LULU|AnalysisDate=9/2/2020 12:00:00 AM|PreviousStop=332.1824|NewStop=372.562428512573|CurrentPriceLow=387.08|CurrentPriceClose=398.29|PriceTrendIndicatorSlope=2.77707505226135|StopLimitId=
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
MGSHSESSIONv2.00
|
MGSHSESSIONv2.00
|
||||||
LastUpdated=2/23/2026 9:37:05 PM
|
LastUpdated=2/13/2026 8:56:00 PM
|
||||||
TradeDate=2/24/2026
|
TradeDate=2/17/2026
|
||||||
StartDate=3/31/2025
|
StartDate=3/31/2025
|
||||||
AnalysisDate=2/23/2026
|
AnalysisDate=2/13/2026
|
||||||
Cycle=11
|
Cycle=11
|
||||||
CashBalance=2932.39
|
CashBalance=2932.39
|
||||||
NonTradeableCash=0
|
NonTradeableCash=0
|
||||||
HedgeCashBalance=3000
|
HedgeCashBalance=3000
|
||||||
Verbose=True|KeepSlotPositions=True|BenchmarkMode=False|BenchmarkModeSymbol=SPY|HoldingPeriod=3|MaxPositions=3|NoTradeSymbols=OSB,IBDRY,GBTC,YOKU,PNY,RFMD,ASAZY|NoTradeFinancialSymbols=U.S. Private Equity,U.S. Financials,U.S. Financial Services,U.S. Banking and Investment Services,Trading-Miscellaneous,Trading--Miscellaneous,Trading--Leveraged Equity,Trading--Leveraged Debt,Trading--Leveraged Commodities,Trading--Inverse Equity,Trading--Inverse Commodities,Tactical Allocation,Specialty Finance,Japan Financials,Savings & Cooperative Banks,Option Writing,Insurance Brokers,Insurance - Specialty,Insurance - Reinsurance,Insurance - Property & Casualty,Insurance - Life,Insurance - Diversified,Global Private Equity,Global Financials,Financial Services,Financial Exchanges,Financial,China Financials,Banks - Regional - US,Banks - Regional - Latin America,Banks - Global,Asset Management,Credit Services|Benchmark=SPY|MarketCapLowerLimit=1000000000|UsePEScreen=False|UseEBITDAScreen=True|UseRevenuePerShareScreen=True|UseLowSlopeBetaCheck=True|LowSlopeBetaDays=15|LowSlopeBetaThreshhold=1|UseMACD=True|MACDSetup=(12,26,9)|MACDSignalDays=12|MACDRejectStrongSellSignals=False|MACDRejectWeakSellSignals=True|UseStochastics=True|StochasticsSignalDays=3|StochasticsRejectStrongSells=True|StochasticsRejectWeakSells=True|UseFallbackCandidate=True|FallbackCandidate=SHV|FallbackCandidateBestOf=SHV,NEAR,BIL,GSY,AGG,ACWX,GSY,SCHF,IXUS,DBEF,IEFA,TLT|UseMaxPEScreen=True|MaxPE=40|StrictMaxPE=False|QualityIndicatorType=IDINDICATOR|IncludeTradeMasterForSymbolsHeld=True|UseStopLimits=True|StopLimitRiskPercentDecimal=0.2|StopLimitScalingVolatilityDays=30|MinDaysBetweenInitialStopAdjustment=30|MinDaysBetweenStopAdjustments=30|StopLimitPriceTrendDays=20|StopLimitATRMultiplier=3|UseHedging=True|HedgeBenchmarkSymbol=SPY|HedgeShortSymbol=SH|HedgeRiskPercentDecimal=0.12|HedgeMinDaysBetweenStopAdjustments=1|HedgeInitialCash=3000|HedgeCloseAboveSMANDays=10|HedgeBandBreakCheckDays=3|HedgeATRMultiplier=1|MaxPricingExceptions=3|UseBetaGenerator=True|UseBetaGeneratorMonths=24
|
Verbose=True|KeepSlotPositions=True|BenchmarkMode=False|BenchmarkModeSymbol=SPY|HoldingPeriod=3|MaxPositions=3|NoTradeSymbols=OSB,IBDRY,GBTC,YOKU,PNY,RFMD,ASAZY|NoTradeFinancialSymbols=U.S. Private Equity,U.S. Financials,U.S. Financial Services,U.S. Banking and Investment Services,Trading-Miscellaneous,Trading--Miscellaneous,Trading--Leveraged Equity,Trading--Leveraged Debt,Trading--Leveraged Commodities,Trading--Inverse Equity,Trading--Inverse Commodities,Tactical Allocation,Specialty Finance,Japan Financials,Savings & Cooperative Banks,Option Writing,Insurance Brokers,Insurance - Specialty,Insurance - Reinsurance,Insurance - Property & Casualty,Insurance - Life,Insurance - Diversified,Global Private Equity,Global Financials,Financial Services,Financial Exchanges,Financial,China Financials,Banks - Regional - US,Banks - Regional - Latin America,Banks - Global,Asset Management,Credit Services|Benchmark=SPY|MarketCapLowerLimit=1000000000|UsePEScreen=False|UseEBITDAScreen=True|UseRevenuePerShareScreen=True|UseLowSlopeBetaCheck=True|LowSlopeBetaDays=15|LowSlopeBetaThreshhold=1|UseMACD=True|MACDSetup=(12,26,9)|MACDSignalDays=12|MACDRejectStrongSellSignals=False|MACDRejectWeakSellSignals=True|UseStochastics=True|StochasticsSignalDays=3|StochasticsRejectStrongSells=True|StochasticsRejectWeakSells=True|UseFallbackCandidate=True|FallbackCandidate=SHV|FallbackCandidateBestOf=SHV,NEAR,BIL,GSY,AGG,ACWX,GSY,SCHF,IXUS,DBEF,IEFA,TLT|UseMaxPEScreen=True|MaxPE=40|StrictMaxPE=False|QualityIndicatorType=IDINDICATOR|IncludeTradeMasterForSymbolsHeld=True|UseStopLimits=True|StopLimitRiskPercentDecimal=0.2|StopLimitScalingVolatilityDays=30|MinDaysBetweenInitialStopAdjustment=30|MinDaysBetweenStopAdjustments=30|StopLimitPriceTrendDays=20|StopLimitATRMultiplier=3|UseHedging=True|HedgeBenchmarkSymbol=SPY|HedgeShortSymbol=SH|HedgeRiskPercentDecimal=0.12|HedgeMinDaysBetweenStopAdjustments=1|HedgeInitialCash=3000|HedgeCloseAboveSMANDays=10|HedgeBandBreakCheckDays=3|HedgeATRMultiplier=1|MaxPricingExceptions=3|UseBetaGenerator=True|UseBetaGeneratorMonths=24
|
||||||
TotalActivePositions=7
|
TotalActivePositions=7
|
||||||
Slot=0|Symbol=USFD|PurchaseDate=9/30/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=12|PurchasePrice=76.21|CurrentPrice=96.13|Volume=2447913|Return1D=0|CumReturn252=0|IDIndicator=-18.7250996015936|Score=0.970794577873616|Velocity=0.708823529411765|PE=33.97|Beta=1.35666771887916|InitialStopLimit=60.97|TrailingStopLimit=90.4222861194611|LastStopAdjustment=2/17/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=15.324|Comment=Price changed on 10/1/2025 from $76.62 to $76.21
|
Slot=0|Symbol=USFD|PurchaseDate=9/30/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=12|PurchasePrice=76.21|CurrentPrice=99.93|Volume=2447913|Return1D=0|CumReturn252=0|IDIndicator=-18.7250996015936|Score=0.970794577873616|Velocity=0.708823529411765|PE=33.97|Beta=1.35666771887916|InitialStopLimit=60.97|TrailingStopLimit=77.9387144756317|LastStopAdjustment=1/15/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=15.324|Comment=Price changed on 10/1/2025 from $76.62 to $76.21
|
||||||
Slot=0|Symbol=CAH|PurchaseDate=9/30/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=5|PurchasePrice=155.81|CurrentPrice=224.82|Volume=2414935|Return1D=0|CumReturn252=0|IDIndicator=-17.9282868525896|Score=1.45705377610136|Velocity=0.779428953080648|PE=23.64|Beta=0.628226122785001|InitialStopLimit=124.65|TrailingStopLimit=198.937214622498|LastStopAdjustment=1/30/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=31.392|Comment=Price changed on 10/1/2025 from $156.96 to $155.81
|
Slot=0|Symbol=CAH|PurchaseDate=9/30/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=5|PurchasePrice=155.81|CurrentPrice=220.79|Volume=2414935|Return1D=0|CumReturn252=0|IDIndicator=-17.9282868525896|Score=1.45705377610136|Velocity=0.779428953080648|PE=23.64|Beta=0.628226122785001|InitialStopLimit=124.65|TrailingStopLimit=198.937214622498|LastStopAdjustment=1/30/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=31.392|Comment=Price changed on 10/1/2025 from $156.96 to $155.81
|
||||||
Slot=0|Symbol=TPB|PurchaseDate=12/31/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=6|PurchasePrice=109|CurrentPrice=135.73|Volume=132784|Return1D=0|CumReturn252=0|IDIndicator=-15.9362549800797|Score=1.44361960940429|Velocity=0.947395388556789|PE=37.1|Beta=1.25054775125095|InitialStopLimit=87.2|TrailingStopLimit=106.557785625458|LastStopAdjustment=1/30/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=21.68|Comment=Price changed on 1/2/2026 from $108.40 to $109.00
|
Slot=0|Symbol=TPB|PurchaseDate=12/31/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=6|PurchasePrice=109|CurrentPrice=131.77|Volume=132784|Return1D=0|CumReturn252=0|IDIndicator=-15.9362549800797|Score=1.44361960940429|Velocity=0.947395388556789|PE=37.1|Beta=1.25054775125095|InitialStopLimit=87.2|TrailingStopLimit=106.557785625458|LastStopAdjustment=1/30/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=21.68|Comment=Price changed on 1/2/2026 from $108.40 to $109.00
|
||||||
Slot=1|Symbol=XEL|PurchaseDate=10/31/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=5|PurchasePrice=81.17|CurrentPrice=83.35|Volume=6202750|Return1D=0|CumReturn252=0|IDIndicator=-11.5537848605578|Score=0.602697377681549|Velocity=0.944803580308304|PE=22.43|Beta=-0.192317961128493|InitialStopLimit=64.936|TrailingStopLimit=77.5441425132751|LastStopAdjustment=2/23/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=16.234|Comment=
|
Slot=1|Symbol=XEL|PurchaseDate=10/31/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=5|PurchasePrice=81.17|CurrentPrice=81.59|Volume=6202750|Return1D=0|CumReturn252=0|IDIndicator=-11.5537848605578|Score=0.602697377681549|Velocity=0.944803580308304|PE=22.43|Beta=-0.192317961128493|InitialStopLimit=64.936|TrailingStopLimit=64.936|LastStopAdjustment=1/1/0001 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=16.234|Comment=
|
||||||
Slot=1|Symbol=MDT|PurchaseDate=1/30/2026 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=14|PurchasePrice=102.85|CurrentPrice=98.61|Volume=6046285|Return1D=0|CumReturn252=0|IDIndicator=-10.3585657370518|Score=0.518428403011861|Velocity=0.865293185419968|PE=26.67|Beta=0.37428296833055|InitialStopLimit=82.28|TrailingStopLimit=82.28|LastStopAdjustment=1/1/0001 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=20.592|Comment=Price changed on 2/2/2026 from $102.96 to $102.85
|
Slot=1|Symbol=MDT|PurchaseDate=1/30/2026 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=14|PurchasePrice=102.85|CurrentPrice=99.49|Volume=6046285|Return1D=0|CumReturn252=0|IDIndicator=-10.3585657370518|Score=0.518428403011861|Velocity=0.865293185419968|PE=26.67|Beta=0.37428296833055|InitialStopLimit=82.28|TrailingStopLimit=82.28|LastStopAdjustment=1/1/0001 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=20.592|Comment=Price changed on 2/2/2026 from $102.96 to $102.85
|
||||||
Slot=1|Symbol=ALHC|PurchaseDate=1/30/2026 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=64|PurchasePrice=22.45|CurrentPrice=19.9|Volume=2524769|Return1D=0|CumReturn252=0|IDIndicator=-8.36653386454184|Score=0.341327585226881|Velocity=0.908249807247494|PE=0|Beta=-0.0198043736453601|InitialStopLimit=17.96|TrailingStopLimit=17.96|LastStopAdjustment=1/1/0001 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=4.506|Comment=Price changed on 2/2/2026 from $22.53 to $22.45
|
Slot=1|Symbol=ALHC|PurchaseDate=1/30/2026 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=64|PurchasePrice=22.45|CurrentPrice=20.19|Volume=2524769|Return1D=0|CumReturn252=0|IDIndicator=-8.36653386454184|Score=0.341327585226881|Velocity=0.908249807247494|PE=0|Beta=-0.0198043736453601|InitialStopLimit=17.96|TrailingStopLimit=17.96|LastStopAdjustment=1/1/0001 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=4.506|Comment=Price changed on 2/2/2026 from $22.53 to $22.45
|
||||||
Slot=2|Symbol=NFG|PurchaseDate=11/28/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=12|PurchasePrice=82.45|CurrentPrice=87.59|Volume=236813|Return1D=0|CumReturn252=0|IDIndicator=-9.56175298804781|Score=1.47874375251707|Velocity=0.658599827139153|PE=31.63|Beta=0.0443025382529758|InitialStopLimit=65.96|TrailingStopLimit=77.9947861814499|LastStopAdjustment=1/30/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=16.49|Comment=
|
Slot=2|Symbol=NFG|PurchaseDate=11/28/2025 12:00:00 AM|SellDate=1/1/0001 12:00:00 AM|Shares=12|PurchasePrice=82.45|CurrentPrice=87.34|Volume=236813|Return1D=0|CumReturn252=0|IDIndicator=-9.56175298804781|Score=1.47874375251707|Velocity=0.658599827139153|PE=31.63|Beta=0.0443025382529758|InitialStopLimit=65.96|TrailingStopLimit=77.9947861814499|LastStopAdjustment=1/30/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=16.49|Comment=
|
||||||
TotalPositions=17
|
TotalPositions=17
|
||||||
Symbol=MO|PurchaseDate=3/31/2025 12:00:00 AM|SellDate=5/14/2025 12:00:00 AM|Shares=18|PurchasePrice=59.91|CurrentPrice=56.15|Volume=17335180|Return1D=0|CumReturn252=0|IDIndicator=-15.9362549800797|Score=1.14749269300042|Velocity=0.967136150234742|PE=9|Beta=0.572465642401382|InitialStopLimit=47.93|TrailingStopLimit=56.1565003347397|LastStopAdjustment=5/7/2025 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=12.004|Comment=Closed due to trailing stop.
|
Symbol=MO|PurchaseDate=3/31/2025 12:00:00 AM|SellDate=5/14/2025 12:00:00 AM|Shares=18|PurchasePrice=59.91|CurrentPrice=56.15|Volume=17335180|Return1D=0|CumReturn252=0|IDIndicator=-15.9362549800797|Score=1.14749269300042|Velocity=0.967136150234742|PE=9|Beta=0.572465642401382|InitialStopLimit=47.93|TrailingStopLimit=56.1565003347397|LastStopAdjustment=5/7/2025 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=12.004|Comment=Closed due to trailing stop.
|
||||||
Symbol=EXC|PurchaseDate=3/31/2025 12:00:00 AM|SellDate=5/14/2025 12:00:00 AM|Shares=24|PurchasePrice=45.76|CurrentPrice=42.6|Volume=14993121|Return1D=0|CumReturn252=0|IDIndicator=-8.76494023904382|Score=0.405636492837393|Velocity=1|PE=18.02|Beta=0.248374476251328|InitialStopLimit=36.61|TrailingStopLimit=42.7107857322693|LastStopAdjustment=4/30/2025 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=9.216|Comment=Closed due to trailing stop.
|
Symbol=EXC|PurchaseDate=3/31/2025 12:00:00 AM|SellDate=5/14/2025 12:00:00 AM|Shares=24|PurchasePrice=45.76|CurrentPrice=42.6|Volume=14993121|Return1D=0|CumReturn252=0|IDIndicator=-8.76494023904382|Score=0.405636492837393|Velocity=1|PE=18.02|Beta=0.248374476251328|InitialStopLimit=36.61|TrailingStopLimit=42.7107857322693|LastStopAdjustment=4/30/2025 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=9.216|Comment=Closed due to trailing stop.
|
||||||
@@ -34,7 +34,7 @@ Symbol=SH|PurchaseDate=9/15/2025 12:00:00 AM|SellDate=11/20/2025 12:00:00 AM|Sha
|
|||||||
Symbol=PSO|PurchaseDate=4/30/2025 12:00:00 AM|SellDate=1/16/2026 12:00:00 AM|Shares=69|PurchasePrice=15.98|CurrentPrice=12.62|Volume=894303|Return1D=0|CumReturn252=0|IDIndicator=-11.9521912350598|Score=1.15269564166514|Velocity=0.737122557726465|PE=19.2|Beta=0.0342052512015139|InitialStopLimit=12.78|TrailingStopLimit=12.78|LastStopAdjustment=1/1/0001 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=3.25|Comment=Closed due to trailing stop.
|
Symbol=PSO|PurchaseDate=4/30/2025 12:00:00 AM|SellDate=1/16/2026 12:00:00 AM|Shares=69|PurchasePrice=15.98|CurrentPrice=12.62|Volume=894303|Return1D=0|CumReturn252=0|IDIndicator=-11.9521912350598|Score=1.15269564166514|Velocity=0.737122557726465|PE=19.2|Beta=0.0342052512015139|InitialStopLimit=12.78|TrailingStopLimit=12.78|LastStopAdjustment=1/1/0001 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=3.25|Comment=Closed due to trailing stop.
|
||||||
Symbol=NYT|PurchaseDate=8/29/2025 12:00:00 AM|SellDate=2/4/2026 12:00:00 AM|Shares=14|PurchasePrice=59.38|CurrentPrice=61.34|Volume=1582847|Return1D=0|CumReturn252=0|IDIndicator=-10.3585657370518|Score=-0.0546472654561472|Velocity=0.878823529411765|PE=30.96|Beta=0.759120105784337|InitialStopLimit=47.5|TrailingStopLimit=66.0039285755157|LastStopAdjustment=1/7/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=11.968|Comment=Manual close.
|
Symbol=NYT|PurchaseDate=8/29/2025 12:00:00 AM|SellDate=2/4/2026 12:00:00 AM|Shares=14|PurchasePrice=59.38|CurrentPrice=61.34|Volume=1582847|Return1D=0|CumReturn252=0|IDIndicator=-10.3585657370518|Score=-0.0546472654561472|Velocity=0.878823529411765|PE=30.96|Beta=0.759120105784337|InitialStopLimit=47.5|TrailingStopLimit=66.0039285755157|LastStopAdjustment=1/7/2026 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=11.968|Comment=Manual close.
|
||||||
Symbol=NEU|PurchaseDate=11/28/2025 12:00:00 AM|SellDate=2/12/2026 12:00:00 AM|Shares=1|PurchasePrice=761.43|CurrentPrice=607|Volume=47592|Return1D=0|CumReturn252=0|IDIndicator=-10.7569721115538|Score=1.32888913206578|Velocity=0.735010364152827|PE=16.57|Beta=0.634028454808648|InitialStopLimit=609.14|TrailingStopLimit=609.14|LastStopAdjustment=1/1/0001 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=152.706|Comment=Closed due to trailing stop.
|
Symbol=NEU|PurchaseDate=11/28/2025 12:00:00 AM|SellDate=2/12/2026 12:00:00 AM|Shares=1|PurchasePrice=761.43|CurrentPrice=607|Volume=47592|Return1D=0|CumReturn252=0|IDIndicator=-10.7569721115538|Score=1.32888913206578|Velocity=0.735010364152827|PE=16.57|Beta=0.634028454808648|InitialStopLimit=609.14|TrailingStopLimit=609.14|LastStopAdjustment=1/1/0001 12:00:00 AM|PositionRiskPercentDecimal=0.2|R=152.706|Comment=Closed due to trailing stop.
|
||||||
TotalStopLimits=38
|
TotalStopLimits=36
|
||||||
Symbol=EXC|AnalysisDate=4/30/2025 12:00:00 AM|PreviousStop=36.61|NewStop=42.7107857322693|CurrentPriceLow=42.6|CurrentPriceClose=46.9|PriceTrendIndicatorSlope=0.0870828032493591|StopLimitId=EXC20250331120000AM
|
Symbol=EXC|AnalysisDate=4/30/2025 12:00:00 AM|PreviousStop=36.61|NewStop=42.7107857322693|CurrentPriceLow=42.6|CurrentPriceClose=46.9|PriceTrendIndicatorSlope=0.0870828032493591|StopLimitId=EXC20250331120000AM
|
||||||
Symbol=SXT|AnalysisDate=4/30/2025 12:00:00 AM|PreviousStop=59.18|NewStop=85.4177850723267|CurrentPriceLow=92.4|CurrentPriceClose=93.95|PriceTrendIndicatorSlope=0.931879639625549|StopLimitId=SXT20250331120000AM
|
Symbol=SXT|AnalysisDate=4/30/2025 12:00:00 AM|PreviousStop=59.18|NewStop=85.4177850723267|CurrentPriceLow=92.4|CurrentPriceClose=93.95|PriceTrendIndicatorSlope=0.931879639625549|StopLimitId=SXT20250331120000AM
|
||||||
Symbol=MO|AnalysisDate=5/7/2025 12:00:00 AM|PreviousStop=47.93|NewStop=56.1565003347397|CurrentPriceLow=56.16|CurrentPriceClose=60.91|PriceTrendIndicatorSlope=0.217300787568092|StopLimitId=MO20250331120000AM
|
Symbol=MO|AnalysisDate=5/7/2025 12:00:00 AM|PreviousStop=47.93|NewStop=56.1565003347397|CurrentPriceLow=56.16|CurrentPriceClose=60.91|PriceTrendIndicatorSlope=0.217300787568092|StopLimitId=MO20250331120000AM
|
||||||
@@ -71,7 +71,5 @@ Symbol=USFD|AnalysisDate=1/15/2026 12:00:00 AM|PreviousStop=73.5799289083481|New
|
|||||||
Symbol=CAH|AnalysisDate=1/30/2026 12:00:00 AM|PreviousStop=194.335500230789|NewStop=198.937214622498|CurrentPriceLow=210.01|CurrentPriceClose=212.42|PriceTrendIndicatorSlope=0.434736758470535|StopLimitId=CAH20250930120000AM
|
Symbol=CAH|AnalysisDate=1/30/2026 12:00:00 AM|PreviousStop=194.335500230789|NewStop=198.937214622498|CurrentPriceLow=210.01|CurrentPriceClose=212.42|PriceTrendIndicatorSlope=0.434736758470535|StopLimitId=CAH20250930120000AM
|
||||||
Symbol=TPB|AnalysisDate=1/30/2026 12:00:00 AM|PreviousStop=87.2|NewStop=106.557785625458|CurrentPriceLow=117.87|CurrentPriceClose=121.15|PriceTrendIndicatorSlope=0.970541477203369|StopLimitId=TPB20251231120000AM
|
Symbol=TPB|AnalysisDate=1/30/2026 12:00:00 AM|PreviousStop=87.2|NewStop=106.557785625458|CurrentPriceLow=117.87|CurrentPriceClose=121.15|PriceTrendIndicatorSlope=0.970541477203369|StopLimitId=TPB20251231120000AM
|
||||||
Symbol=NFG|AnalysisDate=1/30/2026 12:00:00 AM|PreviousStop=65.96|NewStop=77.9947861814499|CurrentPriceLow=82.54|CurrentPriceClose=83.75|PriceTrendIndicatorSlope=0.215090155601501|StopLimitId=NFG20251128120000AM
|
Symbol=NFG|AnalysisDate=1/30/2026 12:00:00 AM|PreviousStop=65.96|NewStop=77.9947861814499|CurrentPriceLow=82.54|CurrentPriceClose=83.75|PriceTrendIndicatorSlope=0.215090155601501|StopLimitId=NFG20251128120000AM
|
||||||
Symbol=USFD|AnalysisDate=2/17/2026 12:00:00 AM|PreviousStop=77.9387144756317|NewStop=90.4222861194611|CurrentPriceLow=96.59|CurrentPriceClose=97.11|PriceTrendIndicatorSlope=0.7435262799263|StopLimitId=USFD20250930120000AM
|
|
||||||
Symbol=XEL|AnalysisDate=2/23/2026 12:00:00 AM|PreviousStop=64.936|NewStop=77.5441425132751|CurrentPriceLow=81.78|CurrentPriceClose=83.35|PriceTrendIndicatorSlope=0.34472182393074|StopLimitId=XEL20251031120000AM
|
|
||||||
TotalHedgePositions=0
|
TotalHedgePositions=0
|
||||||
TotalPricingExceptions=0
|
TotalPricingExceptions=0
|
||||||
|
|||||||
Reference in New Issue
Block a user