Orrery Cycle Toolkit
- Libraries
-
Syarief Azman Bin Rosli
Hello and welcome to my official MQL5 profile!
I am Syarief Azman Bin Rosli, an algorithmic trading systems developer and quantitative software engineer with over a decade of specialized experience creating robust automated trading solutions for MetaTrader 5 and MetaTrader 4. - Version: 1.0
- Activations: 5
An MQL5 library that measures the dominant market cycle of any symbol and timeframe: period in bars, phase, a sine / lead sine pair whose crossings mark cycle turns, cycle or trend mode, amplitude, trendline, spectrum, adaptive indicator lengths and a projection of the current cycle. It only reads price history: it never trades, draws or writes files. You receive the compiled Orrery_Cycle_Toolkit.ex5; this page is the complete API reference.
Quick Start
- Copy Orrery_Cycle_Toolkit.ex5 to MQL5/Libraries (File > Open Data Folder).
- Paste the #import block below into your EA, indicator or script.
- OnInit: h = OCT_Create(_Symbol, PERIOD_CURRENT, OCT_HOMODYNE, 8, 48, 2000).
- OnTick or OnTimer: if OCT_Update(h) returns true, read OCT_Value(h, field, 1). Decide on shift 1, the last closed bar.
- OnDeinit: OCT_Release(h).
- Verify: run the example below on EURUSD H1 in the Strategy Tester; after the warm-up (3 x max_period bars) the log prints the readings on every bar.
Import Declaration (Copy-Paste Ready)
#import "Orrery_Cycle_Toolkit.ex5"
int OCT_Create(string symbol, ENUM_TIMEFRAMES timeframe, int method, int min_period, int max_period, int lookback);
bool OCT_SetParam(int handle, int param, double value);
bool OCT_Update(int handle);
void OCT_Release(int handle);
int OCT_Bars(int handle);
double OCT_Value(int handle, int field, int shift);
int OCT_TurnSignal(int handle, int shift);
int OCT_Spectrum(int handle, int shift, double &power[]);
int OCT_Project(int handle, int bars, double &path[]);
int OCT_AdaptiveLength(int handle, double fraction, int min_len, int max_len, int shift);
int OCT_SuperSmoother(const double &src[], double &dst[], double period);
int OCT_HighPass(const double &src[], double &dst[], double period);
int OCT_Roofing(const double &src[], double &dst[], int min_period, int max_period);
int OCT_CycleSeries(const double &src[], int method, int min_period, int max_period, int field, double &dst[]);
int OCT_DFTSpectrum(const double &src[], int index, int min_period, int max_period, double &power[]);
int OCT_LastError();
string OCT_ErrorText(int code);
#import
enum OCT_METHOD { OCT_HOMODYNE, OCT_AUTOCORR, OCT_DFT };
enum OCT_FIELD { OCT_PERIOD, OCT_RAW_PERIOD, OCT_PHASE, OCT_SINE, OCT_LEADSINE, OCT_FILTER, OCT_TRENDLINE,
OCT_AMPLITUDE, OCT_STRENGTH, OCT_MODE, OCT_PHASE_STEP };
enum OCT_PARAM { OCT_PARAM_PRICE, OCT_PARAM_TREND_BAND, OCT_PARAM_SMOOTHING, OCT_PARAM_AVGLEN }; How It Works
- Roofing filter: a 2-pole high-pass at max_period and a super smoother at min_period keep only cycles between the two lengths (field FILTER).
- Period, by method: 0 Homodyne discriminator (Hilbert transform, fastest), 1 Autocorrelation periodogram (steadiest), 2 DFT spectrum. Methods 1 and 2 use the centre of gravity, in frequency, of the bins at or above half power. Then period = s x raw + (1 - s) x previous (s = smoothing, 0.33).
- Phase: the filter correlated with one cycle of sine and cosine, corrected for the filter's exact phase response at the measured period. 0-360 degrees: 90 = cycle peak, 270 = trough. SINE = sin(phase), LEADSINE = sin(phase + 45).
- Turn: LEADSINE crossing above SINE (+1, cycle low near) or below it (-1, cycle high near).
- Mode: cycle (0) when a turn happened within the last half cycle or the phase advanced 0.67-1.5 x 360/period on the bar; otherwise trend: +1 up or -1 down by price versus TRENDLINE. Always trend when price is at least trend band x AMPLITUDE from TRENDLINE.
- Warm-up: the first 3 x max_period bars return EMPTY_VALUE.
Fields
0 PERIOD: smoothed dominant cycle in bars (min_period to max_period). 1 RAW_PERIOD: unsmoothed measurement. 2 PHASE: degrees, 0-360. 3 SINE and 4 LEADSINE: -1 to +1. 5 FILTER: roofing filter, price units. 6 TRENDLINE: average price over one cycle, smoothed 4-3-2-1. 7 AMPLITUDE: RMS of the filter over one cycle x 1.414, price units. 8 STRENGTH: AMPLITUDE / average bar range over one cycle. 9 MODE: 0 cycle, 1 trend up, -1 trend down. 10 PHASE_STEP: phase advance on the bar, -180 to 180 degrees (360/period in a clean cycle).
API Reference
Shift 0 = forming bar (changes until it closes), 1 = last closed bar; closed bars never change. Every call sets OCT_LastError.
OCT_Create
Opens a tracker. symbol: "" or NULL = chart symbol. timeframe: PERIOD_CURRENT allowed. method: 0-2. min_period: 4-50 (0 = 8). max_period: min_period + 4 to 120 (0 = 48). lookback: bars kept, 0 = 2000, raised to 4 x max_period (at least 200), at most 50000. Returns handle 0-31, or -1 with -1 (bad parameter, unknown symbol) or -2 (32 handles in use). Loads no data yet.
int h = OCT_Create("XAUUSD", PERIOD_M15, OCT_AUTOCORR, 10, 40, 3000); OCT_SetParam
param 0 price: 0 close, 1 median, 2 typical, 3 weighted (default 0). 1 trend band, x AMPLITUDE: 0.1-10 (1.5). 2 smoothing: 0.05-1 (0.33; 1 = none). 3 autocorrelation averaging length: 0-50 (3; 0 = lag length). Other values: false and -1. A changed value rebuilds the tracker on the next OCT_Update; OCT_Bars returns 0 until then.
OCT_Update
Loads history on the first call, then appends new bars and recomputes the forming bar; call it on every tick or timer. true when values exist; false with -3 (bad handle), -4 NO DATA (history still loading: call again) or -5 NOT ENOUGH BARS (under 3 x max_period + 1 bars). Gaps or edited history trigger a rebuild. Above lookback + 500 bars the oldest are dropped; no value changes.
OCT_Release
Frees one handle; -1 frees all. Call it in OnDeinit.
OCT_Bars
Bars with values (shift 0 to OCT_Bars - 1); 0 before the first successful update; -1 for a bad handle.
OCT_Value
Field value at shift. EMPTY_VALUE with -1 (field outside 0-10), -3, or -6 (negative shift, shift beyond OCT_Bars - 1, no update yet).
if(OCT_Value(h, OCT_MODE, 1) == 0 && OCT_TurnSignal(h, 1) == 1) Print("cycle low turn"); OCT_TurnSignal
+1 when LEADSINE crossed above SINE on that bar, -1 below, 0 none or invalid shift. Turns are meant for cycle mode: check MODE. At shift 0 a turn can appear and vanish within the bar.
OCT_Spectrum
Fills power[] with max_period - min_period + 1 values (power[0] = min_period bars), scaled 0-1. Methods 0 and 2: DFT of the filter over max_period bars, strongest bin = 1. Method 1: the smoothed autocorrelation periodogram over its slowly decaying maximum. Returns the count or -1.
OCT_Project
Continues the current cycle from shift 0 for bars (1-500): path[k] = TRENDLINE + slope x (k + 1) + AMPLITUDE x sin(PHASE + 360 x (k + 1) / PERIOD), where slope = TRENDLINE change per bar over the last quarter cycle; path[0] = next bar. Returns bars, or -1 with -1 (bars out of range) or -5 (not ready). A geometric continuation, not a forecast.
OCT_AdaptiveLength
round(PERIOD x fraction) limited to min_len..max_len; fraction above 0 up to 10, 1 <= min_len <= max_len. -1 on error. RSI over half a cycle:
int len = OCT_AdaptiveLength(h, 0.5, 2, 100, 1);
Array functions
No handle, nothing kept between calls. src[] may be chronological or series-indexed; dst[i] belongs to src[i] and dst keeps its own indexing. A dynamic dst is resized; an indicator buffer needs src's size. Return the number of values, or -1 with -1 (bad parameter, dst too small) or -5 (empty or too short). Fixed settings: smoothing 0.33, averaging 3, trend band 1.5; STRENGTH uses the average absolute change of src.
- OCT_SuperSmoother: 2-pole super smoother, period 2-1000; first 2 values copy src.
- OCT_HighPass: 2-pole high-pass, period 2-1000; first 2 values are 0.
- OCT_Roofing: high-pass at max_period, then super smoother at min_period (equals FILTER).
- OCT_CycleSeries: the whole engine on src; dst = field 0-10 per bar, EMPTY_VALUE in the warm-up. Needs 3 x max_period + 1 values.
- OCT_DFTSpectrum: power at src[index] (src's own indexing), scaled like OCT_Spectrum; needs max_period - 1 older values. Returns max_period - min_period + 1, or -1 with -6 (index out of range) or -5.
double c[], per[]; ArraySetAsSeries(c, true); CopyClose(_Symbol, _Period, 0, 500, c); OCT_CycleSeries(c, OCT_HOMODYNE, 8, 48, OCT_PERIOD, per); // per[0] = forming bar
OCT_LastError and OCT_ErrorText
Code of the last call, and its text in capitals: 0 OK, -1 INVALID PARAMETER, -2 NO FREE HANDLE, -3 INVALID HANDLE, -4 NO DATA, -5 NOT ENOUGH BARS, -6 SHIFT OUT OF RANGE, otherwise UNKNOWN.
Working Integration Example
An Expert Advisor: paste the import block and the three enum lines above first.
int h = -1;
datetime last = 0;
int OnInit()
{
h = OCT_Create(_Symbol, PERIOD_CURRENT, OCT_HOMODYNE, 8, 48, 2000);
return(h < 0 ? INIT_FAILED : INIT_SUCCEEDED);
}
void OnDeinit(const int reason) { OCT_Release(h); }
void OnTick()
{
datetime bar = iTime(_Symbol, _Period, 0);
if(bar == last)
return;
if(!OCT_Update(h)) { Print("orrery: ", OCT_ErrorText(OCT_LastError())); return; }
last = bar;
PrintFormat("period %.1f phase %.0f mode %.0f turn %d rsi length %d", OCT_Value(h, OCT_PERIOD, 1),
OCT_Value(h, OCT_PHASE, 1), OCT_Value(h, OCT_MODE, 1), OCT_TurnSignal(h, 1), OCT_AdaptiveLength(h, 0.5, 2, 100, 1));
} Architecture and Notes
- Each handle keeps its own history and results; each importing program has its own 32 handles.
- A tick recomputes only the forming bar (well under 1 ms in tests); the first update of 2,000 bars takes a few to about 100 ms, by method and max_period.
- MetaTrader 5, any symbol and timeframe; EAs, indicators, scripts. Safe in the Strategy Tester, optimization and MQL5 Cloud Network: no DLLs, files, web requests, chart objects, timers or global variables. OCT_Create adds the symbol to Market Watch to load its history.
- Limits: 32 handles per program, periods 4-120 bars, projection up to 500 bars, lookback up to 50000 bars.
- Typical setups. Adaptive lengths: method 0, periods 8-48, RSI length OCT_AdaptiveLength(h, 0.5, 2, 100, 1). Cycle swings: method 1, periods 10-40, act on OCT_TurnSignal(h, 1) only when MODE at shift 1 is 0. Trend filter: MODE not 0 = trend; trend band 2.5 for fewer trend bars. Indicators: OCT_CycleSeries in OnCalculate.
- The screenshots and video show a demonstration EA built on this library; it is not part of the purchase.
Risk Notice
Cycle readings describe past prices. Markets change regime, a projection is not a forecast and no reading guarantees profit. Test on a demo account first.
