commit c8e3e3084937da789232940d231a8c478eb82100 Author: Valentine Chibuike Ozoigboanugo Date: Sun Jun 14 15:32:09 2026 +0200 Initial commit: RangeBars Proprietary trading software. © Teenodi Ltd. All rights reserved. Co-Authored-By: Claude Opus 4.8 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..659b368 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Compiled binaries / logs / terminal artifacts +*.ex4 +*.ex5 +*.log +*.tmp +*.bak diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d7128eb --- /dev/null +++ b/LICENSE @@ -0,0 +1,10 @@ +Copyright (c) 2023-2026 Teenodi Ltd. All rights reserved. + +This software and its source code are the proprietary and confidential +property of Teenodi Ltd. Unauthorized copying, distribution, modification, +public display, or use of this software, in whole or in part, via any medium, +is strictly prohibited without the express prior written permission of +Teenodi Ltd. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. Trading +financial instruments carries risk; use at your own risk. diff --git a/README.md b/README.md new file mode 100644 index 0000000..bc72f2a --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# RangeBars + +Constant-range (range-bar) charting indicator, with the development iterations that led to it archived. + +> **Proprietary software** — © Teenodi Ltd. All rights reserved. Private repository; not for distribution. See [LICENSE](LICENSE). + +## Range_Bars.mq5 + +## Archive + +Earlier versions / forks are preserved under [`archive/`](archive/) for reference. + +## Install + +1. Copy the source file(s) into your MetaTrader 5 `MQL5/` tree (`Experts/`, `Indicators/`, or `Scripts/` as appropriate). +2. In MetaEditor, open the file and compile (**F7**). +3. Attach the compiled program to a chart from the terminal Navigator. + +## License + +Proprietary and confidential. © Teenodi Ltd. All rights reserved. See [LICENSE](LICENSE). diff --git a/Range_Bars.mq5 b/Range_Bars.mq5 new file mode 100644 index 0000000..70f8045 Binary files /dev/null and b/Range_Bars.mq5 differ diff --git a/archive/RangeBar3.mq5 b/archive/RangeBar3.mq5 new file mode 100644 index 0000000..0cc4547 Binary files /dev/null and b/archive/RangeBar3.mq5 differ diff --git a/archive/Range_Bars_Series.mq5 b/archive/Range_Bars_Series.mq5 new file mode 100644 index 0000000..58b7206 Binary files /dev/null and b/archive/Range_Bars_Series.mq5 differ diff --git a/archive/Rangebar3.2.mq5 b/archive/Rangebar3.2.mq5 new file mode 100644 index 0000000..3458843 Binary files /dev/null and b/archive/Rangebar3.2.mq5 differ diff --git a/archive/try.mq5 b/archive/try.mq5 new file mode 100644 index 0000000..45485d0 Binary files /dev/null and b/archive/try.mq5 differ diff --git a/archive/try2.2.mq5 b/archive/try2.2.mq5 new file mode 100644 index 0000000..79259de Binary files /dev/null and b/archive/try2.2.mq5 differ diff --git a/archive/try2.mq5 b/archive/try2.mq5 new file mode 100644 index 0000000..2717e35 Binary files /dev/null and b/archive/try2.mq5 differ diff --git a/archive/try3.mq5 b/archive/try3.mq5 new file mode 100644 index 0000000..ab74bc4 --- /dev/null +++ b/archive/try3.mq5 @@ -0,0 +1,193 @@ + +// [Previous property declarations and input parameters remain unchanged] + +// Global variables for tick synchronization +datetime g_lastSyncTime = 0; +bool g_initialSyncDone = false; +int g_retryCount = 0; +const int MAX_RETRIES = 3; +ulong g_currentChunkStart = 0; +const ulong CHUNK_SIZE = 2592000000; // 30 days in milliseconds + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // [Previous initialization code remains unchanged until before g_lastProcessedTickTime initialization] + + // Initialize with dummy tick to trigger sync + MqlTick dummy; + SymbolInfoTick(_Symbol, dummy); + + // Reset sync variables + g_initialSyncDone = false; + g_retryCount = 0; + + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) +{ + if(rates_total <= 0) + return(0); + + // Calculate historical data on first run + if(!g_initialized) + { + if(!g_initialSyncDone) + { + // Initialize chunk start time + datetime startTime = TimeCurrent() - InpBacklogMinutes * 60; + g_currentChunkStart = startTime * 1000; // Convert to milliseconds + g_initialSyncDone = true; + } + + // Process historical data in chunks + bool continueProcessing = true; + MqlTick historical_ticks[]; + int totalBars = 0; + + while(continueProcessing) + { + ulong chunkEnd = g_currentChunkStart + CHUNK_SIZE; + if(chunkEnd > TimeCurrent() * 1000) + chunkEnd = TimeCurrent() * 1000; + + int copied = CopyTicksRange(_Symbol, historical_ticks, COPY_TICKS_INFO, + g_currentChunkStart, chunkEnd); + + if(copied > 0) + { + // Reset retry count on successful copy + g_retryCount = 0; + + // Process ticks in this chunk + MqlRates tempBuffer[]; + + for(int i = 0; i < copied && totalBars < InpStartingBars; i++) + { + // Filter out irrelevant ticks + if((historical_ticks[i].flags & TICK_FLAG_BID) == 0) + continue; + + if(ProcessHistoricalTick(historical_ticks[i], tempBuffer)) + { + totalBars++; + + if(totalBars >= InpStartingBars) + { + // Write processed bars to custom symbol + if(CustomRatesUpdate(g_customSymbol, tempBuffer)) + { + g_initialized = true; + g_lastProcessedTickTime = historical_ticks[i].time_msc; + continueProcessing = false; + break; + } + } + } + } + + // Move to next chunk if we need more bars + g_currentChunkStart = chunkEnd; + } + else + { + int error = GetLastError(); + if(error == ERR_HISTORY_TIMEOUT) + { + if(g_retryCount < MAX_RETRIES) + { + // Implement exponential backoff + Sleep(1000 * (g_retryCount + 1)); + g_retryCount++; + continue; + } + } + Print("Error copying historical ticks: ", error); + return(0); + } + + // Check if we've reached current time + if(chunkEnd >= TimeCurrent() * 1000) + continueProcessing = false; + } + } + else + { + // Process current ticks using chunked approach + MqlTick current_ticks[]; + ulong fromTime = (g_lastProcessedTickTime - InpTickTolerance * 1000); + ulong toTime = TimeCurrent() * 1000; + + // Split current tick processing into smaller chunks if needed + while(fromTime < toTime) + { + ulong chunkEnd = fromTime + CHUNK_SIZE; + if(chunkEnd > toTime) + chunkEnd = toTime; + + int copied = CopyTicksRange(_Symbol, current_ticks, COPY_TICKS_INFO, + fromTime, chunkEnd); + + if(copied > 0) + { + for(int i = 0; i < copied; i++) + { + // Filter out irrelevant ticks + if((current_ticks[i].flags & TICK_FLAG_BID) == 0) + continue; + + if(current_ticks[i].time_msc > g_lastProcessedTickTime) + { + ProcessTick(current_ticks[i]); + g_lastProcessedTickTime = current_ticks[i].time_msc; + } + } + fromTime = chunkEnd; + } + else + { + int error = GetLastError(); + if(error != ERR_HISTORY_TIMEOUT || g_retryCount >= MAX_RETRIES) + { + Print("Error copying current ticks: ", error); + break; + } + Sleep(1000 * (g_retryCount + 1)); + g_retryCount++; + } + } + } + + ChartRedraw(g_customChartID); + return(rates_total); +} + +// [Previous helper functions remain unchanged] + +//+------------------------------------------------------------------+ +//| Cleanup resources with improved synchronization handling | +//+------------------------------------------------------------------+ +void CleanupResources() +{ + // Reset sync variables + g_initialSyncDone = false; + g_retryCount = 0; + g_currentChunkStart = 0; + + // [Previous cleanup code remains unchanged] +} \ No newline at end of file diff --git a/archive/try6.mq5 b/archive/try6.mq5 new file mode 100644 index 0000000..b6136e9 Binary files /dev/null and b/archive/try6.mq5 differ diff --git a/archive/try7.mq5 b/archive/try7.mq5 new file mode 100644 index 0000000..c5160ab --- /dev/null +++ b/archive/try7.mq5 @@ -0,0 +1,237 @@ +//+------------------------------------------------------------------+ +//| try7.mq5 | +//| Copyright 2025, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#property indicator_separate_window +#property indicator_minimum 1 +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- indicator buffers mapping + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const int begin, + const double &price[]) + { +//--- + +//--- return value of prev_calculated for next call + return(rates_total); + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +// [Previous property declarations and input parameters remain unchanged] + +// Global variables for tick synchronization +datetime g_lastSyncTime = 0; +bool g_initialSyncDone = false; +int g_retryCount = 0; +const int MAX_RETRIES = 3; +ulong g_currentChunkStart = 0; +const ulong CHUNK_SIZE = 2592000000; // 30 days in milliseconds + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // [Previous initialization code remains unchanged until before g_lastProcessedTickTime initialization] + + // Initialize with dummy tick to trigger sync + MqlTick dummy; + SymbolInfoTick(_Symbol, dummy); + + // Reset sync variables + g_initialSyncDone = false; + g_retryCount = 0; + + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) +{ + if(rates_total <= 0) + return(0); + + // Calculate historical data on first run + if(!g_initialized) + { + if(!g_initialSyncDone) + { + // Initialize chunk start time + datetime startTime = TimeCurrent() - InpBacklogMinutes * 60; + g_currentChunkStart = startTime * 1000; // Convert to milliseconds + g_initialSyncDone = true; + } + + // Process historical data in chunks + bool continueProcessing = true; + MqlTick historical_ticks[]; + int totalBars = 0; + + while(continueProcessing) + { + ulong chunkEnd = g_currentChunkStart + CHUNK_SIZE; + if(chunkEnd > TimeCurrent() * 1000) + chunkEnd = TimeCurrent() * 1000; + + int copied = CopyTicksRange(_Symbol, historical_ticks, COPY_TICKS_INFO, + g_currentChunkStart, chunkEnd); + + if(copied > 0) + { + // Reset retry count on successful copy + g_retryCount = 0; + + // Process ticks in this chunk + MqlRates tempBuffer[]; + + for(int i = 0; i < copied && totalBars < InpStartingBars; i++) + { + // Filter out irrelevant ticks + if((historical_ticks[i].flags & TICK_FLAG_BID) == 0) + continue; + + if(ProcessHistoricalTick(historical_ticks[i], tempBuffer)) + { + totalBars++; + + if(totalBars >= InpStartingBars) + { + // Write processed bars to custom symbol + if(CustomRatesUpdate(g_customSymbol, tempBuffer)) + { + g_initialized = true; + g_lastProcessedTickTime = historical_ticks[i].time_msc; + continueProcessing = false; + break; + } + } + } + } + + // Move to next chunk if we need more bars + g_currentChunkStart = chunkEnd; + } + else + { + int error = GetLastError(); + if(error == ERR_HISTORY_TIMEOUT) + { + if(g_retryCount < MAX_RETRIES) + { + // Implement exponential backoff + Sleep(1000 * (g_retryCount + 1)); + g_retryCount++; + continue; + } + } + Print("Error copying historical ticks: ", error); + return(0); + } + + // Check if we've reached current time + if(chunkEnd >= TimeCurrent() * 1000) + continueProcessing = false; + } + } + else + { + // Process current ticks using chunked approach + MqlTick current_ticks[]; + ulong fromTime = (g_lastProcessedTickTime - InpTickTolerance * 1000); + ulong toTime = TimeCurrent() * 1000; + + // Split current tick processing into smaller chunks if needed + while(fromTime < toTime) + { + ulong chunkEnd = fromTime + CHUNK_SIZE; + if(chunkEnd > toTime) + chunkEnd = toTime; + + int copied = CopyTicksRange(_Symbol, current_ticks, COPY_TICKS_INFO, + fromTime, chunkEnd); + + if(copied > 0) + { + for(int i = 0; i < copied; i++) + { + // Filter out irrelevant ticks + if((current_ticks[i].flags & TICK_FLAG_BID) == 0) + continue; + + if(current_ticks[i].time_msc > g_lastProcessedTickTime) + { + ProcessTick(current_ticks[i]); + g_lastProcessedTickTime = current_ticks[i].time_msc; + } + } + fromTime = chunkEnd; + } + else + { + int error = GetLastError(); + if(error != ERR_HISTORY_TIMEOUT || g_retryCount >= MAX_RETRIES) + { + Print("Error copying current ticks: ", error); + break; + } + Sleep(1000 * (g_retryCount + 1)); + g_retryCount++; + } + } + } + + ChartRedraw(g_customChartID); + return(rates_total); +} + +// [Previous helper functions remain unchanged] + +//+------------------------------------------------------------------+ +//| Cleanup resources with improved synchronization handling | +//+------------------------------------------------------------------+ +void CleanupResources() +{ + // Reset sync variables + g_initialSyncDone = false; + g_retryCount = 0; + g_currentChunkStart = 0; + + // [Previous cleanup code remains unchanged] +} \ No newline at end of file