Unit refactoring

Fixed massive heap corruption bug in TDataRecord
This commit is contained in:
Michael Schimmel
2025-07-25 11:54:53 +02:00
parent 6b18d95570
commit aa53a88953
13 changed files with 461 additions and 359 deletions
+44 -43
View File
@@ -8,8 +8,9 @@ uses
System.Generics.Collections,
System.Rtti,
Myc.Data.Records,
Myc.Trade.Types,
Myc.Data.Series;
Myc.Data.Pipeline,
Myc.Data.Series,
Myc.Trade.Types;
type
// Result for the Moving Average Convergence Divergence (MACD) indicator.
@@ -46,48 +47,48 @@ type
class function CalculateWMA(const Series: TSeries<Double>; const Period: Integer): Double; static;
public
// Simple Moving Average
class function CreateSMA(Period: Integer): TConstFunc<Double, Double>; static;
class function CreateSMA(Period: Integer): TConvertFunc<Double, Double>; static;
// Exponential Moving Average
class function CreateEMA(Period: Integer): TConstFunc<Double, Double>; static;
class function CreateEMA(Period: Integer): TConvertFunc<Double, Double>; static;
// Hull Moving Average
class function CreateHMA(Period: Integer): TConstFunc<Double, Double>; static;
class function CreateHMA(Period: Integer): TConvertFunc<Double, Double>; static;
// Relative Strength Index
class function CreateRSI(Period: Integer): TConstFunc<Double, Double>; static;
class function CreateRSI(Period: Integer): TConvertFunc<Double, Double>; static;
// Moving Average Convergence Divergence
class function CreateMACD(FastPeriod, SlowPeriod, SignalPeriod: Integer): TConstFunc<Double, TMacdResult>; overload; static;
class function CreateMACD(FastPeriod, SlowPeriod, SignalPeriod: Integer): TConvertFunc<Double, TMacdResult>; overload; static;
class function CreateMACD(
const EmaFast,
EmaSlow,
EmaSignal: TConstFunc<Double, Double>
): TConstFunc<Double, TMacdResult>; overload; static;
EmaSignal: TConvertFunc<Double, Double>
): TConvertFunc<Double, TMacdResult>; overload; static;
// Stochastic Oscillator
class function CreateStochastic(KPeriod, DPeriod: Integer): TConstFunc<TOhlcItem, TStochasticResult>; overload; static;
class function CreateStochastic(KPeriod, DPeriod: Integer): TConvertFunc<TOhlcItem, TStochasticResult>; overload; static;
class function CreateStochastic(
KPeriod: Integer;
const SmaD: TConstFunc<Double, Double>
): TConstFunc<TOhlcItem, TStochasticResult>; overload; static;
const SmaD: TConvertFunc<Double, Double>
): TConvertFunc<TOhlcItem, TStochasticResult>; overload; static;
// Bollinger Bands
class function CreateBollingerBands(Period: Integer; Multiplier: Double): TConstFunc<Double, TBollingerBandsResult>; static;
class function CreateBollingerBands(Period: Integer; Multiplier: Double): TConvertFunc<Double, TBollingerBandsResult>; static;
// Average True Range
class function CreateATR(Period: Integer): TConstFunc<TOhlcItem, Double>; overload; static;
class function CreateATR(const MovAvgTR: TConstFunc<Double, Double>): TConstFunc<TOhlcItem, Double>; overload; static;
class function CreateATR(Period: Integer): TConvertFunc<TOhlcItem, Double>; overload; static;
class function CreateATR(const MovAvgTR: TConvertFunc<Double, Double>): TConvertFunc<TOhlcItem, Double>; overload; static;
// Keltner Channels
class function CreateKeltnerChannels(
Period: Integer;
Multiplier: Double
): TConstFunc<TOhlcItem, TKeltnerChannelsResult>; overload; static;
): TConvertFunc<TOhlcItem, TKeltnerChannelsResult>; overload; static;
class function CreateKeltnerChannels(
const MovAvgMiddle: TConstFunc<Double, Double>;
const AtrFunc: TConstFunc<TOhlcItem, Double>;
const MovAvgMiddle: TConvertFunc<Double, Double>;
const AtrFunc: TConvertFunc<TOhlcItem, Double>;
Multiplier: Double
): TConstFunc<TOhlcItem, TKeltnerChannelsResult>; overload; static;
): TConvertFunc<TOhlcItem, TKeltnerChannelsResult>; overload; static;
class function CreateMean: TConstFunc<TArray<Double>, Double>; static;
class function CreateMean: TConvertFunc<TArray<Double>, Double>; static;
end;
TIndicatorFactory = class
type
TFunc = TConstFunc<TDataRecord, TDataRecord>;
TFunc = TConvertFunc<TDataRecord, TDataRecord>;
private
FParams: TDataRecord.TLayout;
FInput: TDataRecord.TLayout;
@@ -125,9 +126,9 @@ type
TMACD = class
type
TParam = record
Fast: TConstFunc<Double, Double>;
Slow: TConstFunc<Double, Double>;
Signal: TConstFunc<Double, Double>;
Fast: TConvertFunc<Double, Double>;
Slow: TConvertFunc<Double, Double>;
Signal: TConvertFunc<Double, Double>;
end;
TInput = record
@@ -141,7 +142,7 @@ type
end;
public
class function CreateMACD(const Param: TParam): TConstFunc<TInput, TResult>; static;
class function CreateMACD(const Param: TParam): TConvertFunc<TInput, TResult>; static;
end;
var
@@ -208,7 +209,7 @@ begin
Result := numerator / denominator;
end;
class function TIndicators.CreateBollingerBands(Period: Integer; Multiplier: Double): TConstFunc<Double, TBollingerBandsResult>;
class function TIndicators.CreateBollingerBands(Period: Integer; Multiplier: Double): TConvertFunc<Double, TBollingerBandsResult>;
begin
var sourceData: TSeries<Double>;
Result :=
@@ -231,7 +232,7 @@ begin
end;
end;
class function TIndicators.CreateEMA(Period: Integer): TConstFunc<Double, Double>;
class function TIndicators.CreateEMA(Period: Integer): TConvertFunc<Double, Double>;
begin
var lastEma: Double := Double.NaN;
var sourceData: TSeries<Double>;
@@ -262,7 +263,7 @@ begin
end;
end;
class function TIndicators.CreateHMA(Period: Integer): TConstFunc<Double, Double>;
class function TIndicators.CreateHMA(Period: Integer): TConvertFunc<Double, Double>;
begin
var periodHalf := Period div 2;
var periodSqrt := Round(Sqrt(Period));
@@ -305,13 +306,13 @@ begin
end;
// Standard MACD using EMAs.
class function TIndicators.CreateMACD(FastPeriod, SlowPeriod, SignalPeriod: Integer): TConstFunc<Double, TMacdResult>;
class function TIndicators.CreateMACD(FastPeriod, SlowPeriod, SignalPeriod: Integer): TConvertFunc<Double, TMacdResult>;
begin
Result := CreateMACD(CreateEMA(FastPeriod), CreateEMA(SlowPeriod), CreateEMA(SignalPeriod));
end;
// Creates a MACD indicator from three provided moving average functions.
class function TIndicators.CreateMACD(const EmaFast, EmaSlow, EmaSignal: TConstFunc<Double, Double>): TConstFunc<Double, TMacdResult>;
class function TIndicators.CreateMACD(const EmaFast, EmaSlow, EmaSignal: TConvertFunc<Double, Double>): TConvertFunc<Double, TMacdResult>;
begin
Result :=
function(const Value: Double): TMacdResult
@@ -339,7 +340,7 @@ begin
end;
end;
class function TIndicators.CreateRSI(Period: Integer): TConstFunc<Double, Double>;
class function TIndicators.CreateRSI(Period: Integer): TConvertFunc<Double, Double>;
begin
var avgGain: Double := Double.NaN;
var avgLoss: Double := Double.NaN;
@@ -398,7 +399,7 @@ begin
end;
end;
class function TIndicators.CreateSMA(Period: Integer): TConstFunc<Double, Double>;
class function TIndicators.CreateSMA(Period: Integer): TConvertFunc<Double, Double>;
begin
var sourceData: TSeries<Double>;
Result :=
@@ -413,7 +414,7 @@ begin
end;
// Standard Stochastic Oscillator using an SMA for the %D line.
class function TIndicators.CreateStochastic(KPeriod, DPeriod: Integer): TConstFunc<TOhlcItem, TStochasticResult>;
class function TIndicators.CreateStochastic(KPeriod, DPeriod: Integer): TConvertFunc<TOhlcItem, TStochasticResult>;
begin
Result := CreateStochastic(KPeriod, CreateSMA(DPeriod));
end;
@@ -421,8 +422,8 @@ end;
// Creates a Stochastic Oscillator using an injectable moving average for the %D line.
class function TIndicators.CreateStochastic(
KPeriod: Integer;
const SmaD: TConstFunc<Double, Double>
): TConstFunc<TOhlcItem, TStochasticResult>;
const SmaD: TConvertFunc<Double, Double>
): TConvertFunc<TOhlcItem, TStochasticResult>;
begin
var sourceData: TSeries<TOhlcItem>;
@@ -461,13 +462,13 @@ begin
end;
// Standard ATR using an EMA for smoothing.
class function TIndicators.CreateATR(Period: Integer): TConstFunc<TOhlcItem, Double>;
class function TIndicators.CreateATR(Period: Integer): TConvertFunc<TOhlcItem, Double>;
begin
Result := CreateATR(CreateEMA(Period));
end;
// Calculates the Average True Range (ATR) using an injectable moving average.
class function TIndicators.CreateATR(const MovAvgTR: TConstFunc<Double, Double>): TConstFunc<TOhlcItem, Double>;
class function TIndicators.CreateATR(const MovAvgTR: TConvertFunc<Double, Double>): TConvertFunc<TOhlcItem, Double>;
begin
var sourceData: TSeries<TOhlcItem>;
@@ -495,17 +496,17 @@ begin
end;
// Standard Keltner Channels using an EMA for the middle line and an EMA-based ATR.
class function TIndicators.CreateKeltnerChannels(Period: Integer; Multiplier: Double): TConstFunc<TOhlcItem, TKeltnerChannelsResult>;
class function TIndicators.CreateKeltnerChannels(Period: Integer; Multiplier: Double): TConvertFunc<TOhlcItem, TKeltnerChannelsResult>;
begin
Result := CreateKeltnerChannels(CreateEMA(Period), CreateATR(Period), Multiplier);
end;
// Calculates Keltner Channels using an injectable ATR and middle band moving average.
class function TIndicators.CreateKeltnerChannels(
const MovAvgMiddle: TConstFunc<Double, Double>;
const AtrFunc: TConstFunc<TOhlcItem, Double>;
const MovAvgMiddle: TConvertFunc<Double, Double>;
const AtrFunc: TConvertFunc<TOhlcItem, Double>;
Multiplier: Double
): TConstFunc<TOhlcItem, TKeltnerChannelsResult>;
): TConvertFunc<TOhlcItem, TKeltnerChannelsResult>;
begin
Result :=
function(const Value: TOhlcItem): TKeltnerChannelsResult
@@ -533,7 +534,7 @@ begin
end;
end;
class function TIndicators.CreateMean: TConstFunc<TArray<Double>, Double>;
class function TIndicators.CreateMean: TConvertFunc<TArray<Double>, Double>;
begin
Result :=
function(const Value: TArray<Double>): Double
@@ -548,7 +549,7 @@ begin
end;
// Creates a MACD indicator from three provided moving average functions.
class function TMACD.CreateMACD(const Param: TParam): TConstFunc<TInput, TResult>;
class function TMACD.CreateMACD(const Param: TParam): TConvertFunc<TInput, TResult>;
begin
Result :=
function(const Input: TInput): TResult