forked from animatedread/Warrior_EA
AutoTuneIndicators now defaults to FALSE, and the 33 AD/Wyckoff parameters
it used to search are now inputs.
WHY THE DEFAULT FLIPPED - not because the search is broken. It is correct,
and its own Sidak gate is what proves it: 324 candidates per model on
SP500 H1, "no improvement" on all four topologies (0.00236 -> 0.00236 on
the AD configs, 0.00370 -> 0.00370 on PAI), winner rejected at p=1.0000.
It cannot do better here by construction - it ranks candidates by MARGINAL
MI, and the headline MI is 0.00370 nats against a shuffled null of
0.00379 +/- 0.00061 (p=0.4975), so every candidate is a noise draw and the
maximum over N of them is noise too. The cost is 45-56 min per model in
one synchronous call with no yield, and it was the amplifier for the
handle leak fixed in 33f106d. The EA's own report says it plainest: "no
per-feature indicator retuning will help."
THE INPUT STAYS. TuneIndicatorsByFilter is one function of twelve in
AIBase/AutoTune.mqh; the other eleven are the MI/lag/excursion/geometry
diagnostics that produced every verdict this project relies on, and they
run regardless of this flag. Removing the input invites removing the file.
WHY THE INPUTS WERE NEEDED. All 33 were literals in CADIndicatorTuner's
constructor with no input of any kind, while MA/RSI/MACD/Ichimoku have had
their periods exposed from the start. On the AD configs those indicators
contribute 28 of 64 features per bar. Survivable while the tuner searched
them; indefensible with it off, where they would freeze at values nobody
chose.
CONSOLIDATED 33 -> 18. volClimax/volHigh/rangeClimax/rangeSignificant/
stVolRatio/atr were duplicated verbatim across CumulativeDelta, Wyckoff
Events, Failed Structure and Bar Inversion - the same constants restated
3-4 times. One concept, one input. They are SEEDS: each fans out to the
indicator's own struct field, so with the tuner on it retains full
per-indicator freedom to move them apart. Same contract as PeriodMA.
NO RETRAIN. Every default is byte-identical to the literal it replaces,
and the fingerprint's new ADP token is appended ONLY on deviation
(MACD/Ichimoku/BN/XA convention), gated on the AD features being enabled.
At defaults the token is absent, so every model on disk keeps its filename
and stays loadable. Without that guard, merely EXPOSING these parameters
would have re-keyed every config and forced a from-scratch retrain of all
four topologies for a change that alters no number anywhere.
All-or-nothing rather than per-input, so the token can never encode a
partial picture of what the features were built from.
Compiles clean: 0 errors, 0 warnings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
771 lines
37 KiB
MQL5
771 lines
37 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| ADIndicatorTuner.mqh |
|
|
//| AnimateDread |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#include "..\Variables\IndicatorTuneRanges.mqh"
|
|
//--- flat count of AutoTuneIndicators-tunable params across all 5 AD indicators plus the MA/RSI/MACD/
|
|
//--- Ichimoku feature periods, used to persist/restore the "winning" values in the .nnw file. ATR and
|
|
//--- Volume are intentionally NOT included: ATR's only tunable knob is m_periods, the shared bar lookback
|
|
//--- (ind_Periods); Volume's applied-price type (tick vs real) is kept as a plain manual input
|
|
//--- (VolumeData) since not every symbol has real volume available.
|
|
//--- NOTE changing this value invalidates every persisted tuner block - Unflatten() below refuses a
|
|
//--- size-mismatched array and falls back to the constructor defaults, so any model trained before the
|
|
//--- change loses its previously-tuned indicator params (it says so in the log). That is the accepted
|
|
//--- cost of adding a tunable; the network weights themselves are unaffected.
|
|
#define AD_TUNE_PARAM_COUNT 42
|
|
//+------------------------------------------------------------------+
|
|
//| Currently-active tunable input values for each AD indicator (AutoTuneIndicators search space).
|
|
//| InpContextMode/InpSessionType/InpSessionCount are session choices, not accuracy knobs, and are
|
|
//| hardcoded to the indicators' own defaults in CExpertSignalAIBase::InitAD*() rather than
|
|
//| stored/tuned here.
|
|
//+------------------------------------------------------------------+
|
|
struct SADCumulativeDeltaParams
|
|
{
|
|
int lookback;
|
|
double volClimax, volHigh, rangeClimax, rangeSignificant, stVolRatio, atrMult;
|
|
};
|
|
struct SADShorteningOfThrustParams
|
|
{
|
|
int thrustLookback, minImpulses;
|
|
double sotThreshold;
|
|
};
|
|
struct SADWyckoffEventStreamParams
|
|
{
|
|
int lookback, zigzag;
|
|
double volClimax, volHigh, rangeClimax, rangeSignificant, stVolRatio, atr;
|
|
//--- range-lifecycle knobs added by the 2026-08-02 ADWyckoffEventStream rewrite: how close price must
|
|
//--- come to a boundary to count as revisiting it (touchATR), how far the Automatic Rally/Reaction must
|
|
//--- travel off the climax before the range is confirmed and anchored (arMinATR), and the hard age cap
|
|
//--- after which a range is abandoned (maxRangeBars). All three move which events fire, so all three
|
|
//--- are tuned exactly like the thresholds above.
|
|
double touchATR, arMinATR;
|
|
int maxRangeBars;
|
|
};
|
|
struct SADWyckoffFailedStructureParams
|
|
{
|
|
int lookback, zigzagStrength;
|
|
double volClimax, volHigh, rangeClimax, rangeSignificant, stVolRatio, atrMult;
|
|
};
|
|
struct SADWyckoffSignificantBarInversionParams
|
|
{
|
|
int lookback;
|
|
double rangeSignificant, volumeHigh, atr;
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Class CADIndicatorTuner. |
|
|
//| Owns the AutoTuneIndicators search-space state (current + best-known tunable values for all 5 |
|
|
//| AD indicators) and its own mutation logic (random perturbation, flatten/unflatten for .nnw |
|
|
//| persistence, win/loss bookkeeping) - extracted out of CExpertSignalAIBase (SOLID cleanup) since |
|
|
//| this state and behavior is entirely self-contained: it never touches Net, Train()'s state |
|
|
//| machine, or anything else in CExpertSignalAIBase. CExpertSignalAIBase::TuneIndicatorsAndTrain() |
|
|
//| (which DOES orchestrate Train()/Net/checkpointing around this tuner) stays put - that outer loop |
|
|
//| is exactly as tightly coupled to Train()'s resumable state machine as Train() itself, so it's |
|
|
//| deliberately NOT pulled in here; see this file's declaration comment in ExpertSignalAIBase.mqh |
|
|
//| for the full rationale. |
|
|
//+------------------------------------------------------------------+
|
|
class CADIndicatorTuner
|
|
{
|
|
public:
|
|
SADCumulativeDeltaParams adCumDelta;
|
|
SADShorteningOfThrustParams adSOT;
|
|
SADWyckoffEventStreamParams adWES;
|
|
SADWyckoffFailedStructureParams adWFS;
|
|
SADWyckoffSignificantBarInversionParams adWSBI;
|
|
//--- AI-feature MA/RSI periods (see CExpertSignalAIBase::InitMA()/InitRSI()) - searched the same
|
|
//--- way as the AD indicators above, snapped to MA_PERIOD_PRESETS/RSI_PERIOD_PRESETS so a search
|
|
//--- never lands on a non-standard period. Starts from the Classic Signals PeriodMA/PeriodRSI
|
|
//--- input value; only ever diverges from it once AutoTuneIndicators actually runs a trial. The
|
|
//--- Classic Signals MA/RSI vote itself keeps using the literal input, untouched by this search -
|
|
//--- it needs no training/warm-up, so there's nothing for a tuning trial to validate it against.
|
|
int maPeriod;
|
|
//--- unified MA TYPE (MA_TYPE_PRESETS 0..8), searched alongside maPeriod when the MA feature is on.
|
|
//--- Starts from the MA_Type input; only diverges once a tuning trial runs. Feeds InitMA()'s CiCustom.
|
|
int maType;
|
|
int rsiPeriod;
|
|
//--- MACD feature periods (see CExpertSignalAIBase::InitMACDFeature()) - snapped to
|
|
//--- MACD_*_PRESETS, whose preset sets are built so every fast/slow pair stays legal no matter which
|
|
//--- one a trial perturbs (see InputEnums.mqh). Same "the classic vote keeps the raw input" split as
|
|
//--- maPeriod/rsiPeriod above: Signals\SignalMACD.mqh is untouched by this search.
|
|
int macdFast;
|
|
int macdSlow;
|
|
int macdSignal;
|
|
//--- Ichimoku feature periods (see CExpertSignalAIBase::InitIchimoku()) - snapped to ICHIMOKU_*
|
|
//--- presets, likewise mutually-legal in any combination. Signals\SignalIchimoku.mqh is untouched.
|
|
int ichiTenkan;
|
|
int ichiKijun;
|
|
int ichiSenkou;
|
|
//--- best-known copies of the above, kept during TuneIndicatorsAndTrain() so a losing trial can
|
|
//--- restore rather than drift from a bad candidate - see SaveAsBest()/RestoreBest().
|
|
SADCumulativeDeltaParams bestAdCumDelta;
|
|
SADShorteningOfThrustParams bestAdSOT;
|
|
SADWyckoffEventStreamParams bestAdWES;
|
|
SADWyckoffFailedStructureParams bestAdWFS;
|
|
SADWyckoffSignificantBarInversionParams bestAdWSBI;
|
|
int bestMaPeriod;
|
|
int bestMaType;
|
|
int bestRsiPeriod;
|
|
int bestMacdFast;
|
|
int bestMacdSlow;
|
|
int bestMacdSignal;
|
|
int bestIchiTenkan;
|
|
int bestIchiKijun;
|
|
int bestIchiSenkou;
|
|
CADIndicatorTuner(void);
|
|
//--- flattens/restores the tunable param structs to/from a fixed-size array so they can be
|
|
//--- persisted alongside the network weights (see AI/Network.mqh Save()/Load())
|
|
void Flatten(double &arr[]);
|
|
void Unflatten(const double &arr[]);
|
|
//--- randomly perturbs one tunable param of one enabled AD indicator (or the MA/RSI/MACD/Ichimoku
|
|
//--- periods), within IndicatorTuneRanges.mqh bounds / the logical period presets. The use* args
|
|
//--- mirror CExpertSignalAIBase's m_useADCumulativeDelta/etc. (and m_useMA/m_useRSI/m_useMACD/
|
|
//--- m_useIchimoku) enable flags - no-op if all nine are false.
|
|
//--- Tunable-parameter count across the ENABLED indicators only.
|
|
//--- Defined next to PerturbRandom() in the .mqh body; the two must be changed together.
|
|
int ActiveDimensions(bool useCumDelta, bool useSOT, bool useWES, bool useWFS, bool useWSBI, bool useMA, bool useRSI, bool useMACD, bool useIchimoku);
|
|
//--- Candidate VALUES for one flattened parameter index (see Flatten()'s ordering), for the
|
|
//--- filter-based tuner's coordinate sweep. Discrete params return their exact preset list; continuous
|
|
//--- ones return an evenly-spaced grid across their IndicatorTuneRanges.mqh bounds. Returns the count.
|
|
int ParamCandidates(int paramIdx, double &out[]);
|
|
//--- Which indicator group owns a flattened parameter index - lets the sweep skip parameters whose
|
|
//--- indicator is switched off. 0=CumDelta 1=SOT 2=WES 3=WFS 4=WSBI 5=MA 6=RSI 7=MACD 8=Ichimoku.
|
|
int ParamOwner(int paramIdx);
|
|
void PerturbRandom(bool useCumDelta, bool useSOT, bool useWES, bool useWFS, bool useWSBI, bool useMA, bool useRSI, bool useMACD, bool useIchimoku);
|
|
//--- snapshots current -> best (a winning trial) / restores best -> current (undoing a losing trial)
|
|
void SaveAsBest(void);
|
|
void RestoreBest(void);
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Defaults mirror each CustomIndicators\AD*.mq5 input's own default. |
|
|
//+------------------------------------------------------------------+
|
|
CADIndicatorTuner::CADIndicatorTuner(void)
|
|
{
|
|
//--- Seeded from the AD/Wyckoff inputs (Variables\Inputs.mqh) as of 2026-08-08. These were 33 literals
|
|
//--- here, with no way for an operator to change any of them - fine while AutoTuneIndicators searched
|
|
//--- them, indefensible now that it defaults to false. The shared thresholds fan out to each
|
|
//--- indicator's OWN copy, so the tuner keeps full per-indicator freedom to move them apart; only the
|
|
//--- starting point is shared. Same "this is the seed only" contract as maPeriod/maType below.
|
|
adCumDelta.lookback = ADCD_Lookback;
|
|
adCumDelta.volClimax = Wyk_VolClimaxMult;
|
|
adCumDelta.volHigh = Wyk_VolHighMult;
|
|
adCumDelta.rangeClimax = Wyk_RangeClimaxMult;
|
|
adCumDelta.rangeSignificant = Wyk_RangeSignificantMult;
|
|
adCumDelta.stVolRatio = Wyk_ShortTermVolRatio;
|
|
adCumDelta.atrMult = Wyk_AtrMult;
|
|
adSOT.thrustLookback = SOT_ThrustLookback;
|
|
adSOT.minImpulses = SOT_MinImpulses;
|
|
adSOT.sotThreshold = SOT_Threshold;
|
|
adWES.lookback = WES_Lookback;
|
|
adWES.zigzag = WES_ZigZag;
|
|
adWES.volClimax = Wyk_VolClimaxMult;
|
|
adWES.volHigh = Wyk_VolHighMult;
|
|
adWES.rangeClimax = Wyk_RangeClimaxMult;
|
|
adWES.rangeSignificant = Wyk_RangeSignificantMult;
|
|
adWES.stVolRatio = Wyk_ShortTermVolRatio;
|
|
adWES.atr = Wyk_AtrMult;
|
|
adWES.touchATR = WES_TouchATR;
|
|
adWES.arMinATR = WES_ARMinATR;
|
|
adWES.maxRangeBars = WES_MaxRangeBars;
|
|
adWFS.lookback = WFS_Lookback;
|
|
adWFS.zigzagStrength = WFS_ZigZagStrength;
|
|
adWFS.volClimax = Wyk_VolClimaxMult;
|
|
adWFS.volHigh = Wyk_VolHighMult;
|
|
adWFS.rangeClimax = Wyk_RangeClimaxMult;
|
|
adWFS.rangeSignificant = Wyk_RangeSignificantMult;
|
|
adWFS.stVolRatio = Wyk_ShortTermVolRatio;
|
|
adWFS.atrMult = Wyk_AtrMult;
|
|
adWSBI.lookback = WSBI_Lookback;
|
|
adWSBI.rangeSignificant = Wyk_RangeSignificantMult;
|
|
adWSBI.volumeHigh = Wyk_VolHighMult;
|
|
adWSBI.atr = Wyk_AtrMult;
|
|
maPeriod = PeriodMA;
|
|
maType = MA_Type;
|
|
rsiPeriod = PeriodRSI;
|
|
macdFast = MACD_PeriodFast;
|
|
macdSlow = MACD_PeriodSlow;
|
|
macdSignal = MACD_PeriodSignal;
|
|
ichiTenkan = Ichimoku_PeriodTenkan;
|
|
ichiKijun = Ichimoku_PeriodKijun;
|
|
ichiSenkou = Ichimoku_PeriodSenkou;
|
|
SaveAsBest();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CADIndicatorTuner::Flatten(double &arr[])
|
|
{
|
|
ArrayResize(arr, AD_TUNE_PARAM_COUNT);
|
|
int i = 0;
|
|
arr[i++] = adCumDelta.lookback;
|
|
arr[i++] = adCumDelta.volClimax;
|
|
arr[i++] = adCumDelta.volHigh;
|
|
arr[i++] = adCumDelta.rangeClimax;
|
|
arr[i++] = adCumDelta.rangeSignificant;
|
|
arr[i++] = adCumDelta.stVolRatio;
|
|
arr[i++] = adCumDelta.atrMult;
|
|
arr[i++] = adSOT.thrustLookback;
|
|
arr[i++] = adSOT.minImpulses;
|
|
arr[i++] = adSOT.sotThreshold;
|
|
arr[i++] = adWES.lookback;
|
|
arr[i++] = adWES.zigzag;
|
|
arr[i++] = adWES.volClimax;
|
|
arr[i++] = adWES.volHigh;
|
|
arr[i++] = adWES.rangeClimax;
|
|
arr[i++] = adWES.rangeSignificant;
|
|
arr[i++] = adWES.stVolRatio;
|
|
arr[i++] = adWES.atr;
|
|
arr[i++] = adWES.touchATR;
|
|
arr[i++] = adWES.arMinATR;
|
|
arr[i++] = adWES.maxRangeBars;
|
|
arr[i++] = adWFS.lookback;
|
|
arr[i++] = adWFS.zigzagStrength;
|
|
arr[i++] = adWFS.volClimax;
|
|
arr[i++] = adWFS.volHigh;
|
|
arr[i++] = adWFS.rangeClimax;
|
|
arr[i++] = adWFS.rangeSignificant;
|
|
arr[i++] = adWFS.stVolRatio;
|
|
arr[i++] = adWFS.atrMult;
|
|
arr[i++] = adWSBI.lookback;
|
|
arr[i++] = adWSBI.rangeSignificant;
|
|
arr[i++] = adWSBI.volumeHigh;
|
|
arr[i++] = adWSBI.atr;
|
|
arr[i++] = maPeriod;
|
|
arr[i++] = maType;
|
|
arr[i++] = rsiPeriod;
|
|
arr[i++] = macdFast;
|
|
arr[i++] = macdSlow;
|
|
arr[i++] = macdSignal;
|
|
arr[i++] = ichiTenkan;
|
|
arr[i++] = ichiKijun;
|
|
arr[i++] = ichiSenkou;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Reverse of Flatten(); ints are rounded on the way back in since |
|
|
//| everything is carried as double in the flat array. |
|
|
//+------------------------------------------------------------------+
|
|
void CADIndicatorTuner::Unflatten(const double &arr[])
|
|
{
|
|
if(ArraySize(arr) != AD_TUNE_PARAM_COUNT)
|
|
{
|
|
// A size mismatch means AD_TUNE_PARAM_COUNT changed since this array was persisted (e.g. after
|
|
// a version upgrade) - silently keeping the constructor defaults instead of the loaded values
|
|
// used to discard a previously-tuned indicator's best parameters with zero trace in the log.
|
|
Print(__FUNCTION__ + ": persisted tuner param array size (" + IntegerToString(ArraySize(arr)) +
|
|
") does not match AD_TUNE_PARAM_COUNT (" + IntegerToString(AD_TUNE_PARAM_COUNT) +
|
|
") - discarding it and keeping constructor defaults. This model's previously-tuned indicator parameters are lost.");
|
|
return;
|
|
}
|
|
int i = 0;
|
|
adCumDelta.lookback = (int)MathRound(arr[i++]);
|
|
adCumDelta.volClimax = arr[i++];
|
|
adCumDelta.volHigh = arr[i++];
|
|
adCumDelta.rangeClimax = arr[i++];
|
|
adCumDelta.rangeSignificant = arr[i++];
|
|
adCumDelta.stVolRatio = arr[i++];
|
|
adCumDelta.atrMult = arr[i++];
|
|
adSOT.thrustLookback = (int)MathRound(arr[i++]);
|
|
adSOT.minImpulses = (int)MathRound(arr[i++]);
|
|
adSOT.sotThreshold = arr[i++];
|
|
adWES.lookback = (int)MathRound(arr[i++]);
|
|
adWES.zigzag = (int)MathRound(arr[i++]);
|
|
adWES.volClimax = arr[i++];
|
|
adWES.volHigh = arr[i++];
|
|
adWES.rangeClimax = arr[i++];
|
|
adWES.rangeSignificant = arr[i++];
|
|
adWES.stVolRatio = arr[i++];
|
|
adWES.atr = arr[i++];
|
|
adWES.touchATR = arr[i++];
|
|
adWES.arMinATR = arr[i++];
|
|
adWES.maxRangeBars = (int)MathRound(arr[i++]);
|
|
adWFS.lookback = (int)MathRound(arr[i++]);
|
|
adWFS.zigzagStrength = (int)MathRound(arr[i++]);
|
|
adWFS.volClimax = arr[i++];
|
|
adWFS.volHigh = arr[i++];
|
|
adWFS.rangeClimax = arr[i++];
|
|
adWFS.rangeSignificant = arr[i++];
|
|
adWFS.stVolRatio = arr[i++];
|
|
adWFS.atrMult = arr[i++];
|
|
adWSBI.lookback = (int)MathRound(arr[i++]);
|
|
adWSBI.rangeSignificant = arr[i++];
|
|
adWSBI.volumeHigh = arr[i++];
|
|
adWSBI.atr = arr[i++];
|
|
maPeriod = (int)MathRound(arr[i++]);
|
|
maType = (int)MathRound(arr[i++]);
|
|
rsiPeriod = (int)MathRound(arr[i++]);
|
|
macdFast = (int)MathRound(arr[i++]);
|
|
macdSlow = (int)MathRound(arr[i++]);
|
|
macdSignal = (int)MathRound(arr[i++]);
|
|
ichiTenkan = (int)MathRound(arr[i++]);
|
|
ichiKijun = (int)MathRound(arr[i++]);
|
|
ichiSenkou = (int)MathRound(arr[i++]);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Number of SEARCH DIMENSIONS actually in play - the count of |
|
|
//| tunable parameters across the ENABLED indicators only. |
|
|
//| |
|
|
//| Deliberately defined immediately above PerturbRandom(), because |
|
|
//| the per-group counts below must match that function's own |
|
|
//| `MathRand() % N` arities exactly. Adding a tunable to a group |
|
|
//| there without bumping it here would silently under-size the |
|
|
//| search rather than fail, so the two live together and are read |
|
|
//| together. |
|
|
//| |
|
|
//| This is what replaced the IndicatorTuneTrials input (2026-08-01): |
|
|
//| the right search budget is a function of how big the space is, |
|
|
//| which is knowable here and was never knowable by the user. |
|
|
//+------------------------------------------------------------------+
|
|
int CADIndicatorTuner::ActiveDimensions(bool useCumDelta, bool useSOT, bool useWES, bool useWFS, bool useWSBI, bool useMA, bool useRSI, bool useMACD, bool useIchimoku)
|
|
{
|
|
int d = 0;
|
|
if(useCumDelta)
|
|
d += 7; // lookback, volClimax, + 5 more - see PerturbRandom case 0
|
|
if(useSOT)
|
|
d += 3; // case 1
|
|
if(useWES)
|
|
d += 11; // case 2 - 8 thresholds + touchATR/arMinATR/maxRangeBars
|
|
if(useWFS)
|
|
d += 8; // case 3
|
|
if(useWSBI)
|
|
d += 4; // case 4
|
|
if(useMA)
|
|
d += 2; // period + type - case 5
|
|
if(useRSI)
|
|
d += 1; // period - case 6
|
|
if(useMACD)
|
|
d += 3; // fast, slow, signal - case 7
|
|
if(useIchimoku)
|
|
d += 3; // tenkan, kijun, senkou - case 8
|
|
return d;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Indicator group owning a flattened parameter index. The boundaries|
|
|
//| mirror Flatten()'s write order exactly - change one, change both. |
|
|
//+------------------------------------------------------------------+
|
|
int CADIndicatorTuner::ParamOwner(int paramIdx)
|
|
{
|
|
if(paramIdx < 7) return 0; // adCumDelta: 0..6
|
|
if(paramIdx < 10) return 1; // adSOT: 7..9
|
|
if(paramIdx < 21) return 2; // adWES: 10..20
|
|
if(paramIdx < 29) return 3; // adWFS: 21..28
|
|
if(paramIdx < 33) return 4; // adWSBI: 29..32
|
|
if(paramIdx < 35) return 5; // MA: 33..34 (period, type)
|
|
if(paramIdx == 35) return 6; // RSI: 35
|
|
if(paramIdx < 39) return 7; // MACD: 36..38
|
|
return 8; // Ichimoku: 39..41
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Candidate values for one flattened parameter - see the header. |
|
|
//| |
|
|
//| The discrete parameters return their exact preset lists, the same |
|
|
//| ones PerturbRandom() samples from, so a filter sweep can never |
|
|
//| land on a period the enum does not offer. The continuous AD |
|
|
//| parameters get an evenly-spaced grid across their bounds: |
|
|
//| TUNE_GRID_STEPS points is enough for a marginal-association score |
|
|
//| whose own resolution is a handful of histogram bins, and the cost |
|
|
//| of the sweep is linear in this number. |
|
|
//+------------------------------------------------------------------+
|
|
int CADIndicatorTuner::ParamCandidates(int paramIdx, double &out[])
|
|
{
|
|
#define TUNE_GRID_STEPS 6
|
|
//--- discrete preset lists first (identical to PerturbRandom's)
|
|
if(paramIdx == 33)
|
|
{
|
|
int v[] = {MA_PERIOD_5, MA_PERIOD_8, MA_PERIOD_9, MA_PERIOD_10, MA_PERIOD_13,
|
|
MA_PERIOD_20, MA_PERIOD_21, MA_PERIOD_50, MA_PERIOD_100, MA_PERIOD_200};
|
|
ArrayResize(out, ArraySize(v));
|
|
for(int i = 0; i < ArraySize(v); i++) out[i] = v[i];
|
|
return ArraySize(out);
|
|
}
|
|
if(paramIdx == 34)
|
|
{
|
|
int v[] = {MA_TYPE_SMA, MA_TYPE_EMA, MA_TYPE_SMMA, MA_TYPE_LWMA, MA_TYPE_ALMA,
|
|
MA_TYPE_DEMA, MA_TYPE_ZLEMA, MA_TYPE_T3, MA_TYPE_KALMAN};
|
|
ArrayResize(out, ArraySize(v));
|
|
for(int i = 0; i < ArraySize(v); i++) out[i] = v[i];
|
|
return ArraySize(out);
|
|
}
|
|
if(paramIdx == 35)
|
|
{
|
|
int v[] = {RSI_PERIOD_2, RSI_PERIOD_5, RSI_PERIOD_7, RSI_PERIOD_9, RSI_PERIOD_14, RSI_PERIOD_21, RSI_PERIOD_25};
|
|
ArrayResize(out, ArraySize(v));
|
|
for(int i = 0; i < ArraySize(v); i++) out[i] = v[i];
|
|
return ArraySize(out);
|
|
}
|
|
if(paramIdx == 36)
|
|
{
|
|
int v[] = {MACD_FAST_5, MACD_FAST_8, MACD_FAST_12, MACD_FAST_15};
|
|
ArrayResize(out, ArraySize(v));
|
|
for(int i = 0; i < ArraySize(v); i++) out[i] = v[i];
|
|
return ArraySize(out);
|
|
}
|
|
if(paramIdx == 37)
|
|
{
|
|
int v[] = {MACD_SLOW_17, MACD_SLOW_21, MACD_SLOW_26, MACD_SLOW_34, MACD_SLOW_50};
|
|
ArrayResize(out, ArraySize(v));
|
|
for(int i = 0; i < ArraySize(v); i++) out[i] = v[i];
|
|
return ArraySize(out);
|
|
}
|
|
if(paramIdx == 38)
|
|
{
|
|
int v[] = {MACD_SIGNAL_5, MACD_SIGNAL_7, MACD_SIGNAL_9, MACD_SIGNAL_12};
|
|
ArrayResize(out, ArraySize(v));
|
|
for(int i = 0; i < ArraySize(v); i++) out[i] = v[i];
|
|
return ArraySize(out);
|
|
}
|
|
if(paramIdx == 39)
|
|
{
|
|
int v[] = {ICHI_TENKAN_7, ICHI_TENKAN_9, ICHI_TENKAN_12, ICHI_TENKAN_20};
|
|
ArrayResize(out, ArraySize(v));
|
|
for(int i = 0; i < ArraySize(v); i++) out[i] = v[i];
|
|
return ArraySize(out);
|
|
}
|
|
if(paramIdx == 40)
|
|
{
|
|
int v[] = {ICHI_KIJUN_22, ICHI_KIJUN_26, ICHI_KIJUN_30, ICHI_KIJUN_40};
|
|
ArrayResize(out, ArraySize(v));
|
|
for(int i = 0; i < ArraySize(v); i++) out[i] = v[i];
|
|
return ArraySize(out);
|
|
}
|
|
if(paramIdx == 41)
|
|
{
|
|
int v[] = {ICHI_SENKOU_44, ICHI_SENKOU_52, ICHI_SENKOU_60, ICHI_SENKOU_120};
|
|
ArrayResize(out, ArraySize(v));
|
|
for(int i = 0; i < ArraySize(v); i++) out[i] = v[i];
|
|
return ArraySize(out);
|
|
}
|
|
//--- continuous AD parameters: even grid over the tune-range bounds. `isInt` keeps bar-count
|
|
//--- parameters whole, so a candidate is never a fractional lookback.
|
|
double lo = 0, hi = 0;
|
|
bool isInt = false;
|
|
switch(paramIdx)
|
|
{
|
|
case 0: lo = ADCUMDELTA_LOOKBACK_MIN; hi = ADCUMDELTA_LOOKBACK_MAX; isInt = true; break;
|
|
case 1: lo = ADCUMDELTA_VOLCLIMAX_MIN; hi = ADCUMDELTA_VOLCLIMAX_MAX; break;
|
|
case 2: lo = ADCUMDELTA_VOLHIGH_MIN; hi = ADCUMDELTA_VOLHIGH_MAX; break;
|
|
case 3: lo = ADCUMDELTA_RANGECLIMAX_MIN; hi = ADCUMDELTA_RANGECLIMAX_MAX; break;
|
|
case 4: lo = ADCUMDELTA_RANGESIGNIF_MIN; hi = ADCUMDELTA_RANGESIGNIF_MAX; break;
|
|
case 5: lo = ADCUMDELTA_STVOLRATIO_MIN; hi = ADCUMDELTA_STVOLRATIO_MAX; break;
|
|
case 6: lo = ADCUMDELTA_ATRMULT_MIN; hi = ADCUMDELTA_ATRMULT_MAX; break;
|
|
case 7: lo = ADSOT_LOOKBACK_MIN; hi = ADSOT_LOOKBACK_MAX; isInt = true; break;
|
|
case 8: lo = ADSOT_MININPULSES_MIN; hi = ADSOT_MININPULSES_MAX; isInt = true; break;
|
|
case 9: lo = ADSOT_THRESHOLD_MIN; hi = ADSOT_THRESHOLD_MAX; break;
|
|
case 10: lo = ADWES_LOOKBACK_MIN; hi = ADWES_LOOKBACK_MAX; isInt = true; break;
|
|
case 11: lo = ADWES_ZIGZAG_MIN; hi = ADWES_ZIGZAG_MAX; isInt = true; break;
|
|
case 12: lo = ADWES_VOLCLIMAX_MIN; hi = ADWES_VOLCLIMAX_MAX; break;
|
|
case 13: lo = ADWES_VOLHIGH_MIN; hi = ADWES_VOLHIGH_MAX; break;
|
|
case 14: lo = ADWES_RANGECLIMAX_MIN; hi = ADWES_RANGECLIMAX_MAX; break;
|
|
case 15: lo = ADWES_RANGESIGNIF_MIN; hi = ADWES_RANGESIGNIF_MAX; break;
|
|
case 16: lo = ADWES_STVOLRATIO_MIN; hi = ADWES_STVOLRATIO_MAX; break;
|
|
case 17: lo = ADWES_ATR_MIN; hi = ADWES_ATR_MAX; break;
|
|
case 18: lo = ADWES_TOUCHATR_MIN; hi = ADWES_TOUCHATR_MAX; break;
|
|
case 19: lo = ADWES_ARMINATR_MIN; hi = ADWES_ARMINATR_MAX; break;
|
|
case 20: lo = ADWES_MAXRANGEBARS_MIN; hi = ADWES_MAXRANGEBARS_MAX; isInt = true; break;
|
|
case 21: lo = ADWFS_LOOKBACK_MIN; hi = ADWFS_LOOKBACK_MAX; isInt = true; break;
|
|
case 22: lo = ADWFS_ZIGZAGSTRENGTH_MIN; hi = ADWFS_ZIGZAGSTRENGTH_MAX; isInt = true; break;
|
|
case 23: lo = ADWFS_VOLCLIMAX_MIN; hi = ADWFS_VOLCLIMAX_MAX; break;
|
|
case 24: lo = ADWFS_VOLHIGH_MIN; hi = ADWFS_VOLHIGH_MAX; break;
|
|
case 25: lo = ADWFS_RANGECLIMAX_MIN; hi = ADWFS_RANGECLIMAX_MAX; break;
|
|
case 26: lo = ADWFS_RANGESIGNIF_MIN; hi = ADWFS_RANGESIGNIF_MAX; break;
|
|
case 27: lo = ADWFS_STVOLRATIO_MIN; hi = ADWFS_STVOLRATIO_MAX; break;
|
|
case 28: lo = ADWFS_ATRMULT_MIN; hi = ADWFS_ATRMULT_MAX; break;
|
|
case 29: lo = ADWSBI_LOOKBACK_MIN; hi = ADWSBI_LOOKBACK_MAX; isInt = true; break;
|
|
case 30: lo = ADWSBI_RANGESIGNIF_MIN; hi = ADWSBI_RANGESIGNIF_MAX; break;
|
|
case 31: lo = ADWSBI_VOLHIGH_MIN; hi = ADWSBI_VOLHIGH_MAX; break;
|
|
case 32: lo = ADWSBI_ATR_MIN; hi = ADWSBI_ATR_MAX; break;
|
|
default: ArrayResize(out, 0); return 0;
|
|
}
|
|
ArrayResize(out, TUNE_GRID_STEPS);
|
|
for(int i = 0; i < TUNE_GRID_STEPS; i++)
|
|
{
|
|
double v = lo + (hi - lo) * i / (TUNE_GRID_STEPS - 1.0);
|
|
out[i] = isInt ? MathRound(v) : v;
|
|
}
|
|
return TUNE_GRID_STEPS;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Randomly perturbs one tunable param of one randomly-chosen |
|
|
//| *enabled* AD indicator, within IndicatorTuneRanges.mqh bounds. |
|
|
//| No-op if no AD indicator is enabled. |
|
|
//+------------------------------------------------------------------+
|
|
void CADIndicatorTuner::PerturbRandom(bool useCumDelta, bool useSOT, bool useWES, bool useWFS, bool useWSBI, bool useMA, bool useRSI, bool useMACD, bool useIchimoku)
|
|
{
|
|
int enabled[9], n = 0;
|
|
if(useCumDelta)
|
|
enabled[n++] = 0;
|
|
if(useSOT)
|
|
enabled[n++] = 1;
|
|
if(useWES)
|
|
enabled[n++] = 2;
|
|
if(useWFS)
|
|
enabled[n++] = 3;
|
|
if(useWSBI)
|
|
enabled[n++] = 4;
|
|
if(useMA)
|
|
enabled[n++] = 5;
|
|
if(useRSI)
|
|
enabled[n++] = 6;
|
|
if(useMACD)
|
|
enabled[n++] = 7;
|
|
if(useIchimoku)
|
|
enabled[n++] = 8;
|
|
if(n == 0)
|
|
return;
|
|
switch(enabled[MathRand() % n])
|
|
{
|
|
case 0:
|
|
{
|
|
switch(MathRand() % 7)
|
|
{
|
|
case 0:
|
|
adCumDelta.lookback = ADCUMDELTA_LOOKBACK_MIN + MathRand() % (ADCUMDELTA_LOOKBACK_MAX - ADCUMDELTA_LOOKBACK_MIN + 1);
|
|
break;
|
|
case 1:
|
|
adCumDelta.volClimax = ADCUMDELTA_VOLCLIMAX_MIN + (MathRand() / 32767.0) * (ADCUMDELTA_VOLCLIMAX_MAX - ADCUMDELTA_VOLCLIMAX_MIN);
|
|
break;
|
|
case 2:
|
|
adCumDelta.volHigh = ADCUMDELTA_VOLHIGH_MIN + (MathRand() / 32767.0) * (ADCUMDELTA_VOLHIGH_MAX - ADCUMDELTA_VOLHIGH_MIN);
|
|
break;
|
|
case 3:
|
|
adCumDelta.rangeClimax = ADCUMDELTA_RANGECLIMAX_MIN + (MathRand() / 32767.0) * (ADCUMDELTA_RANGECLIMAX_MAX - ADCUMDELTA_RANGECLIMAX_MIN);
|
|
break;
|
|
case 4:
|
|
adCumDelta.rangeSignificant = ADCUMDELTA_RANGESIGNIF_MIN + (MathRand() / 32767.0) * (ADCUMDELTA_RANGESIGNIF_MAX - ADCUMDELTA_RANGESIGNIF_MIN);
|
|
break;
|
|
case 5:
|
|
adCumDelta.stVolRatio = ADCUMDELTA_STVOLRATIO_MIN + (MathRand() / 32767.0) * (ADCUMDELTA_STVOLRATIO_MAX - ADCUMDELTA_STVOLRATIO_MIN);
|
|
break;
|
|
case 6:
|
|
adCumDelta.atrMult = ADCUMDELTA_ATRMULT_MIN + (MathRand() / 32767.0) * (ADCUMDELTA_ATRMULT_MAX - ADCUMDELTA_ATRMULT_MIN);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
switch(MathRand() % 3)
|
|
{
|
|
case 0:
|
|
adSOT.thrustLookback = ADSOT_LOOKBACK_MIN + MathRand() % (ADSOT_LOOKBACK_MAX - ADSOT_LOOKBACK_MIN + 1);
|
|
break;
|
|
case 1:
|
|
adSOT.minImpulses = ADSOT_MININPULSES_MIN + MathRand() % (ADSOT_MININPULSES_MAX - ADSOT_MININPULSES_MIN + 1);
|
|
break;
|
|
case 2:
|
|
adSOT.sotThreshold = ADSOT_THRESHOLD_MIN + (MathRand() / 32767.0) * (ADSOT_THRESHOLD_MAX - ADSOT_THRESHOLD_MIN);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
switch(MathRand() % 11)
|
|
{
|
|
case 0:
|
|
adWES.lookback = ADWES_LOOKBACK_MIN + MathRand() % (ADWES_LOOKBACK_MAX - ADWES_LOOKBACK_MIN + 1);
|
|
break;
|
|
case 1:
|
|
adWES.zigzag = ADWES_ZIGZAG_MIN + MathRand() % (ADWES_ZIGZAG_MAX - ADWES_ZIGZAG_MIN + 1);
|
|
break;
|
|
case 2:
|
|
adWES.volClimax = ADWES_VOLCLIMAX_MIN + (MathRand() / 32767.0) * (ADWES_VOLCLIMAX_MAX - ADWES_VOLCLIMAX_MIN);
|
|
break;
|
|
case 3:
|
|
adWES.volHigh = ADWES_VOLHIGH_MIN + (MathRand() / 32767.0) * (ADWES_VOLHIGH_MAX - ADWES_VOLHIGH_MIN);
|
|
break;
|
|
case 4:
|
|
adWES.rangeClimax = ADWES_RANGECLIMAX_MIN + (MathRand() / 32767.0) * (ADWES_RANGECLIMAX_MAX - ADWES_RANGECLIMAX_MIN);
|
|
break;
|
|
case 5:
|
|
adWES.rangeSignificant = ADWES_RANGESIGNIF_MIN + (MathRand() / 32767.0) * (ADWES_RANGESIGNIF_MAX - ADWES_RANGESIGNIF_MIN);
|
|
break;
|
|
case 6:
|
|
adWES.stVolRatio = ADWES_STVOLRATIO_MIN + (MathRand() / 32767.0) * (ADWES_STVOLRATIO_MAX - ADWES_STVOLRATIO_MIN);
|
|
break;
|
|
case 7:
|
|
adWES.atr = ADWES_ATR_MIN + (MathRand() / 32767.0) * (ADWES_ATR_MAX - ADWES_ATR_MIN);
|
|
break;
|
|
case 8:
|
|
adWES.touchATR = ADWES_TOUCHATR_MIN + (MathRand() / 32767.0) * (ADWES_TOUCHATR_MAX - ADWES_TOUCHATR_MIN);
|
|
break;
|
|
case 9:
|
|
adWES.arMinATR = ADWES_ARMINATR_MIN + (MathRand() / 32767.0) * (ADWES_ARMINATR_MAX - ADWES_ARMINATR_MIN);
|
|
break;
|
|
case 10:
|
|
adWES.maxRangeBars = ADWES_MAXRANGEBARS_MIN + MathRand() % (ADWES_MAXRANGEBARS_MAX - ADWES_MAXRANGEBARS_MIN + 1);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case 3:
|
|
{
|
|
switch(MathRand() % 8)
|
|
{
|
|
case 0:
|
|
adWFS.lookback = ADWFS_LOOKBACK_MIN + MathRand() % (ADWFS_LOOKBACK_MAX - ADWFS_LOOKBACK_MIN + 1);
|
|
break;
|
|
case 1:
|
|
adWFS.zigzagStrength = ADWFS_ZIGZAGSTRENGTH_MIN + MathRand() % (ADWFS_ZIGZAGSTRENGTH_MAX - ADWFS_ZIGZAGSTRENGTH_MIN + 1);
|
|
break;
|
|
case 2:
|
|
adWFS.volClimax = ADWFS_VOLCLIMAX_MIN + (MathRand() / 32767.0) * (ADWFS_VOLCLIMAX_MAX - ADWFS_VOLCLIMAX_MIN);
|
|
break;
|
|
case 3:
|
|
adWFS.volHigh = ADWFS_VOLHIGH_MIN + (MathRand() / 32767.0) * (ADWFS_VOLHIGH_MAX - ADWFS_VOLHIGH_MIN);
|
|
break;
|
|
case 4:
|
|
adWFS.rangeClimax = ADWFS_RANGECLIMAX_MIN + (MathRand() / 32767.0) * (ADWFS_RANGECLIMAX_MAX - ADWFS_RANGECLIMAX_MIN);
|
|
break;
|
|
case 5:
|
|
adWFS.rangeSignificant = ADWFS_RANGESIGNIF_MIN + (MathRand() / 32767.0) * (ADWFS_RANGESIGNIF_MAX - ADWFS_RANGESIGNIF_MIN);
|
|
break;
|
|
case 6:
|
|
adWFS.stVolRatio = ADWFS_STVOLRATIO_MIN + (MathRand() / 32767.0) * (ADWFS_STVOLRATIO_MAX - ADWFS_STVOLRATIO_MIN);
|
|
break;
|
|
case 7:
|
|
adWFS.atrMult = ADWFS_ATRMULT_MIN + (MathRand() / 32767.0) * (ADWFS_ATRMULT_MAX - ADWFS_ATRMULT_MIN);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case 4:
|
|
{
|
|
switch(MathRand() % 4)
|
|
{
|
|
case 0:
|
|
adWSBI.lookback = ADWSBI_LOOKBACK_MIN + MathRand() % (ADWSBI_LOOKBACK_MAX - ADWSBI_LOOKBACK_MIN + 1);
|
|
break;
|
|
case 1:
|
|
adWSBI.rangeSignificant = ADWSBI_RANGESIGNIF_MIN + (MathRand() / 32767.0) * (ADWSBI_RANGESIGNIF_MAX - ADWSBI_RANGESIGNIF_MIN);
|
|
break;
|
|
case 2:
|
|
adWSBI.volumeHigh = ADWSBI_VOLHIGH_MIN + (MathRand() / 32767.0) * (ADWSBI_VOLHIGH_MAX - ADWSBI_VOLHIGH_MIN);
|
|
break;
|
|
case 3:
|
|
adWSBI.atr = ADWSBI_ATR_MIN + (MathRand() / 32767.0) * (ADWSBI_ATR_MAX - ADWSBI_ATR_MIN);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case 5:
|
|
{
|
|
//--- the MA feature has TWO tunables now (period + type); pick one at random to perturb
|
|
if(MathRand() % 2 == 0)
|
|
{
|
|
//--- snapped to MA_PERIOD_PRESETS (InputEnums.mqh) so a search never lands on a non-standard period
|
|
int maChoices[] = {MA_PERIOD_5, MA_PERIOD_8, MA_PERIOD_9, MA_PERIOD_10, MA_PERIOD_13, MA_PERIOD_20, MA_PERIOD_21, MA_PERIOD_50, MA_PERIOD_100, MA_PERIOD_200};
|
|
maPeriod = maChoices[MathRand() % ArraySize(maChoices)];
|
|
}
|
|
else
|
|
{
|
|
//--- unified MA type 0..8 (MA_TYPE_PRESETS): SMA/EMA/SMMA/LWMA/ALMA/DEMA/ZLEMA/T3/Kalman
|
|
int maTypeChoices[] = {MA_TYPE_SMA, MA_TYPE_EMA, MA_TYPE_SMMA, MA_TYPE_LWMA, MA_TYPE_ALMA, MA_TYPE_DEMA, MA_TYPE_ZLEMA, MA_TYPE_T3, MA_TYPE_KALMAN};
|
|
maType = maTypeChoices[MathRand() % ArraySize(maTypeChoices)];
|
|
}
|
|
break;
|
|
}
|
|
case 6:
|
|
{
|
|
//--- snapped to RSI_PERIOD_PRESETS (InputEnums.mqh)
|
|
int rsiChoices[] = {RSI_PERIOD_2, RSI_PERIOD_5, RSI_PERIOD_7, RSI_PERIOD_9, RSI_PERIOD_14, RSI_PERIOD_21, RSI_PERIOD_25};
|
|
rsiPeriod = rsiChoices[MathRand() % ArraySize(rsiChoices)];
|
|
break;
|
|
}
|
|
case 7:
|
|
{
|
|
//--- the MACD feature has THREE tunables (fast/slow/signal); pick one at random. No cross-check
|
|
//--- against the others is needed - the MACD_*_PRESETS sets never overlap, so any fast is always
|
|
//--- below any slow (see InputEnums.mqh).
|
|
switch(MathRand() % 3)
|
|
{
|
|
case 0:
|
|
{
|
|
int fastChoices[] = {MACD_FAST_5, MACD_FAST_8, MACD_FAST_12, MACD_FAST_15};
|
|
macdFast = fastChoices[MathRand() % ArraySize(fastChoices)];
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
int slowChoices[] = {MACD_SLOW_17, MACD_SLOW_21, MACD_SLOW_26, MACD_SLOW_34, MACD_SLOW_50};
|
|
macdSlow = slowChoices[MathRand() % ArraySize(slowChoices)];
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
int signalChoices[] = {MACD_SIGNAL_5, MACD_SIGNAL_7, MACD_SIGNAL_9, MACD_SIGNAL_12};
|
|
macdSignal = signalChoices[MathRand() % ArraySize(signalChoices)];
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 8:
|
|
{
|
|
//--- the Ichimoku feature has THREE tunables (Tenkan/Kijun/Senkou B); pick one at random. Same
|
|
//--- non-overlapping-presets guarantee as MACD above keeps Tenkan < Kijun < Senkou B holding
|
|
//--- whichever single one this trial moves.
|
|
switch(MathRand() % 3)
|
|
{
|
|
case 0:
|
|
{
|
|
int tenkanChoices[] = {ICHI_TENKAN_7, ICHI_TENKAN_9, ICHI_TENKAN_12, ICHI_TENKAN_20};
|
|
ichiTenkan = tenkanChoices[MathRand() % ArraySize(tenkanChoices)];
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
int kijunChoices[] = {ICHI_KIJUN_22, ICHI_KIJUN_26, ICHI_KIJUN_30, ICHI_KIJUN_40};
|
|
ichiKijun = kijunChoices[MathRand() % ArraySize(kijunChoices)];
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
int senkouChoices[] = {ICHI_SENKOU_44, ICHI_SENKOU_52, ICHI_SENKOU_60, ICHI_SENKOU_120};
|
|
ichiSenkou = senkouChoices[MathRand() % ArraySize(senkouChoices)];
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CADIndicatorTuner::SaveAsBest(void)
|
|
{
|
|
bestAdCumDelta = adCumDelta;
|
|
bestAdSOT = adSOT;
|
|
bestAdWES = adWES;
|
|
bestAdWFS = adWFS;
|
|
bestAdWSBI = adWSBI;
|
|
bestMaPeriod = maPeriod;
|
|
bestMaType = maType;
|
|
bestRsiPeriod = rsiPeriod;
|
|
bestMacdFast = macdFast;
|
|
bestMacdSlow = macdSlow;
|
|
bestMacdSignal = macdSignal;
|
|
bestIchiTenkan = ichiTenkan;
|
|
bestIchiKijun = ichiKijun;
|
|
bestIchiSenkou = ichiSenkou;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CADIndicatorTuner::RestoreBest(void)
|
|
{
|
|
adCumDelta = bestAdCumDelta;
|
|
adSOT = bestAdSOT;
|
|
adWES = bestAdWES;
|
|
adWFS = bestAdWFS;
|
|
adWSBI = bestAdWSBI;
|
|
maPeriod = bestMaPeriod;
|
|
maType = bestMaType;
|
|
rsiPeriod = bestRsiPeriod;
|
|
macdFast = bestMacdFast;
|
|
macdSlow = bestMacdSlow;
|
|
macdSignal = bestMacdSignal;
|
|
ichiTenkan = bestIchiTenkan;
|
|
ichiKijun = bestIchiKijun;
|
|
ichiSenkou = bestIchiSenkou;
|
|
}
|
|
//+------------------------------------------------------------------+
|