!MTH Renko Chart Builder Indi Ver 03_new_nmc
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «!mth renko chart builder indi ver 03_new_nmc.mq5» отправится на рассмотрение. Укажите контакт для ответа и опишите причину.
О программе
Индикатор «!MTH Renko Chart Builder» строит офлайн-графики типа Renko на платформе MetaTrader 5. Он обрабатывает исторические и текущие тиковые данные, формирует свечные бары Renko и записывает их в файлы истории (.hst), которые затем отображаются как офлайн-чарты.
Поддерживаются два независимых Renko-графика с отдельными настройками размера ящика, сдвига, таймфрейма и отображения фитилей. При инициализации индикатор автоматически определяет стартовую цену по минимуму за заданный период, если параметр StartingPrice не задан вручную.
Для обновления офлайн-окна используются системные сообщения Windows (PostMessageW / RegisterWindowMessageW), поэтому для работы требуется разрешение на вызов DLL. Индикатор корректирует размер ящика в зависимости от количества знаков после запятой у инструмента (3, 4, 5 или 6 цифр).
Настройки программы
| Настройка | Описание |
|---|---|
| StartingPrice | Стартовая цена для запуска обработки Renko-баров; если равна 0, рассчитывается автоматически по минимуму за MaxBars |
| RenkoBoxSize1 | Размер ящика в пунктах для первого Renko-графика |
| BoxShiftPercent1 | Процент сдвига ящика для первого Renko-графика, используемый для уменьшения шума при построении баров |
| RenkoTimeFrame1 | Таймфрейм для первого офлайн Renko-графика (например, M2 = 2) |
| RenkoBoxOffset1 | Смещение ящика для первого Renko-графика, должно быть меньше по модулю чем RenkoBoxSize1 |
| ShowWicks1 | Отображение фитилей (максимум/минимум) на первом Renko-графике |
| MaxBars1 | Максимальное количество баров исторических данных для обработки первым Renko-графиком |
| Use2ndRenkoChart | Включает второй Renko-график с отдельными параметрами размера, сдвига и таймфрейма |
| RenkoBoxSize2 | Размер ящика в пунктах для второго Renko-графика |
| BoxShiftPercent2 | Процент сдвига ящика для второго Renko-графика, используемый для уменьшения шума при построении баров |
| RenkoTimeFrame2 | Таймфрейм для второго офлайн Renko-графика (например, M3 = 3) |
| RenkoBoxOffset2 | Смещение ящика для второго Renko-графика, должно быть меньше по модулю чем RenkoBoxSize2 |
| ShowWicks2 | Отображение фитилей (максимум/минимум) на втором Renko-графике |
| MaxBars2 | Максимальное количество баров исторических данных для обработки вторым Renko-графиком |
| EmulateOnLineChart | Включает эмуляцию обновления офлайн-графика через системные сообщения Windows на текущем графике |
| StrangeSymbolName | Использовать сокращённое имя символа (первые 6 символов) при создании офлайн-графика |
Поиск по коду файла
#property version "1.00"
#property strict
#property indicator_chart_window
#include <WinUser32.mqh>
#include <stdlib.mqh>
#import "user32.dll"
int RegisterWindowMessageW(string lpString);
int GetWindowTextW(int hWnd,string lpString,int nMaxCount);
int PostMessageW(int hWnd,int Msg,int wParam,int lParam);
#import
extern double StartingPrice = 0;
extern int RenkoBoxSize1 = 10;
extern double BoxShiftPercent1 = 15;
extern int RenkoTimeFrame1 = 2;
extern int RenkoBoxOffset1 = 0;
extern bool ShowWicks1 = true;
extern int MaxBars1 = 5000;
extern bool Use2ndRenkoChart = false;
extern int RenkoBoxSize2 = 20;
extern double BoxShiftPercent2 = 15;
extern int RenkoTimeFrame2 = 3;
extern int RenkoBoxOffset2 = 0;
extern bool ShowWicks2 = true;
extern int MaxBars2 = 5000;
extern bool EmulateOnLineChart= true;
extern bool StrangeSymbolName = true;
int HstHandle1 = -1, MT4InternalMsg1 = 0;
int HstHandle2 = -1, MT4InternalMsg2 = 0;
ulong LastFPos1 = 0, LastFPos2 = 0;
string SymbolName;
string symbol;
int OnInit()
{
// код доступен только после оплаты
}
void UpdateChart1_Window()
{
static int hwnd1 = 0;
if(hwnd1 == 0) {
hwnd1 = WindowHandle(SymbolName, RenkoTimeFrame1);
if(hwnd1 != 0) Print("Chart window ",hwnd1," found");
}
if(EmulateOnLineChart && MT4InternalMsg1 == 0)
MT4InternalMsg1 = RegisterWindowMessageW("MetaTrader4_Internal_Message"); //setup an Internal_Message channel for this mt4 chart
if(hwnd1 != 0) if(PostMessageW(hwnd1, WM_COMMAND, 0x822c, 0) == 0) hwnd1 = 0; //wake up chart1 window
if(hwnd1 != 0 && MT4InternalMsg1 != 0) PostMessageW(hwnd1, MT4InternalMsg1, 2, 1); //send message
return;
}
void UpdateChart2_Window()
{
static int hwnd2 = 0;
if(hwnd2 == 0) {
hwnd2 = WindowHandle(SymbolName, RenkoTimeFrame2);
if(hwnd2 != 0) Print("Chart window ",hwnd2," found");
}
if(EmulateOnLineChart && MT4InternalMsg2 == 0)
MT4InternalMsg2 = RegisterWindowMessageW("MetaTrader4_Internal_Message");
if(hwnd2 != 0) if(PostMessageW(hwnd2, WM_COMMAND, 0x822c, 0) == 0) hwnd2 = 0;
if(hwnd2 != 0 && MT4InternalMsg2 != 0) PostMessageW(hwnd2, MT4InternalMsg2, 2, 1);
return;
}
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[])
{
// код доступен только после оплаты
}
static double BoxPoints1, UpWick1, DnWick1;
static double PrevLow1, PrevHigh1, PrevOpen1, PrevClose1, CurVolume1, CurLow1, CurHigh1, CurOpen1, CurClose1;
static datetime PrevTime1;
MqlRates rates; //copy time series data
if(HstHandle1 < 0)
{
StartingPrice = Low[iLowest(symbol,0,MODE_LOW,MaxBars1,0)];
if(!IsDllsAllowed()) {
Print("Error: Dll calls must be allowed!");
return(-1);
}
if(MathAbs(RenkoBoxOffset1) >= RenkoBoxSize1) {
Print("Error: |RenkoBoxOffset| should be less then RenkoBoxSize1!");
return(-1);
}
int BoxSize1 = RenkoBoxSize1;
int BoxOffset1 = RenkoBoxOffset1;
if(Digits == 5 || (Digits == 3 && StringFind(symbol, "JPY") != -1)) {
BoxSize1 = BoxSize1*10;
BoxOffset1 = BoxOffset1*10;
}
if(Digits == 6 || (Digits == 4 && StringFind(symbol, "JPY") != -1)) {
BoxSize1 = BoxSize1*100;
BoxOffset1 = BoxOffset1*100;
}
if(StrangeSymbolName) SymbolName = StringSubstr(symbol, 0, 6);
else SymbolName = symbol;
BoxPoints1 = NormalizeDouble(BoxSize1*Point, Digits);//Digits);
if (Close[Bars-1]>= StartingPrice)
{
PrevLow1 = NormalizeDouble(BoxOffset1*Point + MathFloor((Close[Bars-1]-StartingPrice)/BoxPoints1)*BoxPoints1 + StartingPrice, Digits);
}
if (Close[Bars-1]< StartingPrice)
{
PrevLow1 = NormalizeDouble(BoxOffset1*Point + StartingPrice - MathCeil((StartingPrice-Close[Bars-1])/BoxPoints1)*BoxPoints1 - Point, Digits);
}
DnWick1 = PrevLow1;
PrevHigh1 = PrevLow1 + BoxPoints1;
UpWick1 = PrevHigh1;
PrevOpen1 = PrevLow1;
PrevClose1 = PrevHigh1;
CurVolume1 = 1;
PrevTime1 = Time[Bars-1];
HstHandle1 = FileOpenHistory(SymbolName + (string)RenkoTimeFrame1 + ".hst", FILE_BIN|FILE_WRITE|FILE_ANSI);
FileClose(HstHandle1); HstHandle1 = -1;
HstHandle1 = FileOpenHistory(SymbolName + (string)RenkoTimeFrame1 + ".hst", FILE_BIN|FILE_READ|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_ANSI);
if(HstHandle1< 0) {
Print("Error: can\'t create / open history file: " + ErrorDescription(GetLastError()) + ": " + SymbolName + IntegerToString(RenkoTimeFrame1) + ".hst");
return(-1);
}
int HstUnused1[13];
FileWriteInteger(HstHandle1, 401, LONG_VALUE); // Version
FileWriteString(HstHandle1, "", 64); // Copyright
FileWriteString(HstHandle1, SymbolName, 12); // Symbol
FileWriteInteger(HstHandle1, RenkoTimeFrame1, LONG_VALUE); // Period
FileWriteInteger(HstHandle1, Digits, LONG_VALUE); // Digits
FileWriteInteger(HstHandle1, 0, LONG_VALUE); // Time Sign
FileWriteInteger(HstHandle1, 0, LONG_VALUE); // Last Sync
FileWriteArray(HstHandle1, HstUnused1, 0, 13); // Unused
int i1 = Bars-2;
if (i1>MaxBars1) i1=MaxBars1;
while(i1 >= 0) {
CurVolume1 = CurVolume1 + Volume[i1];
UpWick1 = MathMax(UpWick1, High[i1]);
DnWick1 = MathMin(DnWick1, Low[i1]);
bool UpTrend1 = High[i1]+Low[i1] > High[i1+1]+Low[i1+1];
while(!UpTrend1 && (Low[i1] < PrevLow1-(BoxShiftPercent1/100)*BoxPoints1
|| CompareDoubles(Low[i1], PrevLow1-(BoxShiftPercent1/100)*BoxPoints1)))
{
PrevHigh1 = PrevHigh1 - (BoxShiftPercent1/100)* BoxPoints1;
PrevLow1 = PrevLow1 - (BoxShiftPercent1/100)*BoxPoints1;
PrevOpen1 = PrevHigh1;
PrevClose1 = PrevLow1;
rates.time = PrevTime1;
rates.open = PrevOpen1;
rates.low = PrevLow1;
if(ShowWicks1 && UpWick1 > PrevHigh1)
rates.high = UpWick1;
else rates.high = PrevHigh1;
rates.close = PrevClose1;
rates.real_volume = (long)CurVolume1;
rates.tick_volume = (long)CurVolume1;
FileWriteStruct(HstHandle1,rates);
UpWick1 = 0;
DnWick1 = EMPTY_VALUE;
CurVolume1 = 0;
CurHigh1 = PrevLow1;
CurLow1 = PrevLow1;
if(PrevTime1 < Time[i1]) PrevTime1 = Time[i1];
else PrevTime1++;
}
while(High[i1] > PrevHigh1+(BoxShiftPercent1/100)*BoxPoints1 || CompareDoubles(High[i1], PrevHigh1+(BoxShiftPercent1/100)*BoxPoints1)) {
PrevHigh1 = PrevHigh1 + (BoxShiftPercent1/100)*BoxPoints1;
PrevLow1 = PrevLow1 + (BoxShiftPercent1/100)*BoxPoints1;
PrevOpen1 = PrevLow1;
PrevClose1 = PrevHigh1;
rates.time = PrevTime1;
rates.open = PrevOpen1;
rates.high = PrevHigh1;
if(ShowWicks1 && DnWick1 < PrevLow1)
rates.low = DnWick1;
else rates.low = PrevLow1;
rates.close = PrevClose1;
rates.real_volume = (long)CurVolume1;
rates.tick_volume = (long)CurVolume1;
FileWriteStruct(HstHandle1,rates);
UpWick1 = 0;
DnWick1 = EMPTY_VALUE;
CurVolume1 = 0;
CurHigh1 = PrevHigh1;
CurLow1 = PrevHigh1;
if(PrevTime1 < Time[i1]) PrevTime1 = Time[i1];
else PrevTime1++;
}
while(UpTrend1 && (Low[i1] < PrevLow1-(BoxShiftPercent1/100)*BoxPoints1 || CompareDoubles(Low[i1], PrevLow1-(BoxShiftPercent1/100)*BoxPoints1))) {
PrevHigh1 = PrevHigh1 - (BoxShiftPercent1/100)*BoxPoints1;
PrevLow1 = PrevLow1 - (BoxShiftPercent1/100)*BoxPoints1;
PrevOpen1 = PrevHigh1;
PrevClose1 = PrevLow1;
rates.time = PrevTime1;
rates.open = PrevOpen1;
rates.low = PrevLow1;
if(ShowWicks1 && UpWick1 > PrevHigh1)
rates.high = UpWick1;
else rates.high = PrevHigh1;
rates.close = PrevClose1;
rates.real_volume = (long)CurVolume1;
rates.tick_volume = (long)CurVolume1;
FileWriteStruct(HstHandle1,rates);
UpWick1 = 0;
DnWick1 = EMPTY_VALUE;
CurVolume1 = 0;
CurHigh1 = PrevLow1;
CurLow1 = PrevLow1;
if(PrevTime1 < Time[i1]) PrevTime1 = Time[i1];
else PrevTime1++;
}
i1--;
}
LastFPos1 = FileTell(HstHandle1); // Remember Last pos in file
if(Close[0] > MathMax(PrevClose1, PrevOpen1)) CurOpen1 = MathMax(PrevClose1, PrevOpen1);
else if (Close[0] < MathMin(PrevClose1, PrevOpen1)) CurOpen1 = MathMin(PrevClose1, PrevOpen1);
else CurOpen1 = Close[0];
CurClose1 = Close[0];
if(UpWick1 > PrevHigh1) CurHigh1 = UpWick1;
if(DnWick1 < PrevLow1) CurLow1 = DnWick1;
rates.time = PrevTime1;
rates.open = CurOpen1;
rates.low = CurLow1;
rates.high = CurHigh1;
rates.close = CurClose1;
rates.real_volume = (long)CurVolume1;
rates.tick_volume = (long)CurVolume1;
FileWriteStruct(HstHandle1,rates);
FileFlush(HstHandle1);
UpdateChart1_Window();
return(0);
}
UpWick1 = MathMax(UpWick1, Bid);
DnWick1 = MathMin(DnWick1, Bid);
CurVolume1++;
FileSeek(HstHandle1, LastFPos1, SEEK_SET);
if(Bid > PrevHigh1+(BoxShiftPercent1/100)*BoxPoints1 || CompareDoubles(Bid, PrevHigh1+(BoxShiftPercent1/100)*BoxPoints1)) {
PrevHigh1 = PrevHigh1 + (BoxShiftPercent1/100)*BoxPoints1;
PrevLow1 = PrevLow1 + (BoxShiftPercent1/100)*BoxPoints1;
PrevOpen1 = PrevLow1;
PrevClose1 = PrevHigh1;
rates.time = PrevTime1;
rates.open = PrevOpen1;
rates.high = PrevHigh1;
if(ShowWicks1 && DnWick1 < PrevLow1)
rates.low = DnWick1;
else rates.low = PrevLow1;
rates.close = PrevClose1;
rates.real_volume = (long)CurVolume1;
rates.tick_volume = (long)CurVolume1;
FileWriteStruct(HstHandle1,rates);
FileFlush(HstHandle1);
LastFPos1 = FileTell(HstHandle1); // Remember Last pos in file
if(PrevTime1 < TimeCurrent()) PrevTime1 = TimeCurrent();
else PrevTime1++;
CurVolume1 = 0;
CurHigh1 = PrevHigh1;
CurLow1 = PrevHigh1;
UpWick1 = 0;
DnWick1 = EMPTY_VALUE;
UpdateChart1_Window();
}
else if(Bid < PrevLow1-(BoxShiftPercent1/100)*BoxPoints1 || CompareDoubles(Bid,PrevLow1-(BoxShiftPercent1/100)*BoxPoints1)) {
PrevHigh1 = PrevHigh1 - (BoxShiftPercent1/100)*BoxPoints1;
PrevLow1 = PrevLow1 - (BoxShiftPercent1/100)*BoxPoints1;
PrevOpen1 = PrevHigh1;
PrevClose1 = PrevLow1;
rates.time = PrevTime1;
rates.open = PrevOpen1;
rates.low = PrevLow1;
if(ShowWicks1 && UpWick1> PrevHigh1)
rates.high = UpWick1;
else rates.high = PrevHigh1;
rates.close = PrevClose1;
rates.real_volume = (long)CurVolume1;
rates.tick_volume = (long)CurVolume1;
FileWriteStruct(HstHandle1,rates);
FileFlush(HstHandle1);
LastFPos1 = Показано первые 50% кода (символов: 17004)
Открыть по тарифу
Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.
Разовая покупка файла
На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.
Зачем нужен email? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.