Skip to content

Commit 2b95a1f

Browse files
authored
1.01
1. Added an option to switch timeframes for all charts with a single keyboard shortcut. 2. Added processing of arrow keys and page up/down keys. 3. Added a small signature (letters "STK") in the bottom left corner of the chart to show that the indicator is attached to the current chart. 4. Fixed processing of some special case keys (like [ and ]).
1 parent 8241fe6 commit 2b95a1f

File tree

2 files changed

+320
-189
lines changed

2 files changed

+320
-189
lines changed

SwitchTimeframesKeys.mq4

Lines changed: 147 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
//| https://www.earnforex.com/ |
55
//+------------------------------------------------------------------+
66
#property copyright "Copyright © 2025, www.EarnForex.com"
7-
#property link "https://www.earnforex.com/metatrader-indicators/SwitchTimeframesKeys/"
8-
#property version "1.00"
7+
#property link "https://www.earnforex.com/indicators/SwitchTimeframesKeys/"
8+
#property version "1.01"
99
#property strict
1010

1111
#property description "Switches timeframes using keyboard shortcuts."
@@ -29,6 +29,9 @@ input string MN = "9";
2929
input string SwitchDown = "Z";
3030
input string SwitchUp = "X";
3131
input string SwitchThrough = "M1, M5, M15, M30, H1, H4, D1, W1, MN";
32+
input string ____Configuration = "=== Configuration ===";
33+
input bool ChangeAllCharts = false;
34+
input bool EnableSignature = true;
3235

3336
ENUM_TIMEFRAMES TF_Array[];
3437
uchar MainKey_M1 = 0, MainKey_M5 = 0, MainKey_M15 = 0, MainKey_M30 = 0, MainKey_H1 = 0, MainKey_H4 = 0, MainKey_D1 = 0, MainKey_W1 = 0, MainKey_MN = 0, MainKey_SwitchDown = 0, MainKey_SwitchUp = 0;
@@ -62,6 +65,16 @@ void OnInit()
6265
else MainKey_SwitchUp = 0;
6366

6467
PrepareSwitchThroughArray();
68+
69+
if (EnableSignature) ShowSignature();
70+
}
71+
72+
void OnDeinit(const int reason)
73+
{
74+
if (EnableSignature)
75+
{
76+
ObjectDelete(ChartID(), "STK_Signature");
77+
}
6578
}
6679

6780
// A dummy function because everything is handled in OnChartEvent().
@@ -86,147 +99,108 @@ void OnChartEvent(const int id,
8699
const string &sparam)
87100
{
88101
if (id != CHARTEVENT_KEYDOWN) return;
89-
90-
if ((MainKey_M1 != 0) && (lparam == MainKey_M1)
102+
103+
// Get Unicode key value.
104+
short key = TranslateKey((int)lparam);
105+
// In case of falire, use raw value.
106+
if (key == -1) key = (short)lparam;
107+
108+
if ((MainKey_M1 != 0) && (key == MainKey_M1)
91109
&& ((((!ShiftRequired_M1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_M1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
92110
&& (((!CtrlRequired_M1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_M1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
93111
)
94112
{
95-
ChartSetSymbolPeriod(ChartID(), Symbol(), PERIOD_M1);
113+
ChangeToSpecificTimeFrame(PERIOD_M1);
96114
}
97-
else if ((MainKey_M5 != 0) && (lparam == MainKey_M5)
115+
else if ((MainKey_M5 != 0) && (key == MainKey_M5)
98116
&& ((((!ShiftRequired_M5) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_M5) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
99117
&& (((!CtrlRequired_M5) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_M5) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
100118
)
101119
{
102-
ChartSetSymbolPeriod(ChartID(), Symbol(), PERIOD_M5);
120+
ChangeToSpecificTimeFrame(PERIOD_M5);
103121
}
104-
else if ((MainKey_M15 != 0) && (lparam == MainKey_M15)
122+
else if ((MainKey_M15 != 0) && (key == MainKey_M15)
105123
&& ((((!ShiftRequired_M15) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_M15) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
106124
&& (((!CtrlRequired_M15) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_M15) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
107125
)
108126
{
109-
ChartSetSymbolPeriod(ChartID(), Symbol(), PERIOD_M15);
127+
ChangeToSpecificTimeFrame(PERIOD_M15);
110128
}
111-
else if ((MainKey_M30 != 0) && (lparam == MainKey_M30)
129+
else if ((MainKey_M30 != 0) && (key == MainKey_M30)
112130
&& ((((!ShiftRequired_M30) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_M30) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
113131
&& (((!CtrlRequired_M30) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_M30) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
114132
)
115133
{
116-
ChartSetSymbolPeriod(ChartID(), Symbol(), PERIOD_M30);
134+
ChangeToSpecificTimeFrame(PERIOD_M30);
117135
}
118-
else if ((MainKey_H1 != 0) && (lparam == MainKey_H1)
136+
else if ((MainKey_H1 != 0) && (key == MainKey_H1)
119137
&& ((((!ShiftRequired_H1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_H1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
120138
&& (((!CtrlRequired_H1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_H1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
121139
)
122140
{
123-
ChartSetSymbolPeriod(ChartID(), Symbol(), PERIOD_H1);
141+
ChangeToSpecificTimeFrame(PERIOD_H1);
124142
}
125-
else if ((MainKey_H4 != 0) && (lparam == MainKey_H4)
143+
else if ((MainKey_H4 != 0) && (key == MainKey_H4)
126144
&& ((((!ShiftRequired_H4) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_H4) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
127145
&& (((!CtrlRequired_H4) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_H4) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
128146
)
129147
{
130-
ChartSetSymbolPeriod(ChartID(), Symbol(), PERIOD_H4);
148+
ChangeToSpecificTimeFrame(PERIOD_H4);
131149
}
132-
else if ((MainKey_D1 != 0) && (lparam == MainKey_D1)
150+
else if ((MainKey_D1 != 0) && (key == MainKey_D1)
133151
&& ((((!ShiftRequired_D1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_D1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
134152
&& (((!CtrlRequired_D1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_D1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
135153
)
136154
{
137-
ChartSetSymbolPeriod(ChartID(), Symbol(), PERIOD_D1);
155+
ChangeToSpecificTimeFrame(PERIOD_D1);
138156
}
139-
else if ((MainKey_W1 != 0) && (lparam == MainKey_W1)
157+
else if ((MainKey_W1 != 0) && (key == MainKey_W1)
140158
&& ((((!ShiftRequired_W1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_W1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
141159
&& (((!CtrlRequired_W1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_W1) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
142160
)
143161
{
144-
ChartSetSymbolPeriod(ChartID(), Symbol(), PERIOD_W1);
162+
ChangeToSpecificTimeFrame(PERIOD_W1);
145163
}
146-
else if ((MainKey_MN != 0) && (lparam == MainKey_MN)
164+
else if ((MainKey_MN != 0) && (key == MainKey_MN)
147165
&& ((((!ShiftRequired_MN) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_MN) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
148166
&& (((!CtrlRequired_MN) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_MN) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
149167
)
150168
{
151-
ChartSetSymbolPeriod(ChartID(), Symbol(), PERIOD_MN1);
169+
ChangeToSpecificTimeFrame(PERIOD_MN1);
152170
}
153-
else if ((MainKey_SwitchDown != 0) && (lparam == MainKey_SwitchDown)
171+
else if ((MainKey_SwitchDown != 0) && (key == MainKey_SwitchDown)
154172
&& ((((!ShiftRequired_SwitchDown) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_SwitchDown) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
155173
&& (((!CtrlRequired_SwitchDown) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_SwitchDown) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
156174
)
157175
{
158-
if (ArraySize(TF_Array) == 0) return;
159-
bool tf_found = false;
160-
for (int i = 0; i < ArraySize(TF_Array); i++)
176+
if (ChangeAllCharts)
161177
{
162-
if (Period() == TF_Array[i]) // Easy - the TF has been found.
178+
for (long chart = ChartFirst(); chart >= 0; chart = ChartNext(chart))
163179
{
164-
if (i > 0) i--;
165-
else i = ArraySize(TF_Array) - 1;
166-
ChartSetSymbolPeriod(ChartID(), Symbol(), TF_Array[i]);
167-
tf_found = true;
168-
break;
169-
}
170-
}
171-
if (!tf_found) // Difficult - TF not found.
172-
{
173-
// Find the first TF > current one:
174-
for (int i = 0; i < ArraySize(TF_Array); i++)
175-
{
176-
if (PeriodSeconds() < PeriodSeconds(TF_Array[i]))
180+
if (chart != ChartID())
177181
{
178-
if (i > 0) i--;
179-
else i = ArraySize(TF_Array) - 1;
180-
ChartSetSymbolPeriod(ChartID(), Symbol(), TF_Array[i]);
181-
tf_found = true;
182-
break;
182+
ChartSetSymbolPeriod(chart, ChartSymbol(chart), GetLowerTimeFrame(ChartPeriod(chart)));
183183
}
184184
}
185-
if (!tf_found) // If once again not found - i.e., all TFs are below the current one:
186-
{
187-
// Switch to the last one.
188-
ChartSetSymbolPeriod(ChartID(), Symbol(), TF_Array[ArraySize(TF_Array) - 1]);
189-
}
190185
}
186+
ChartSetSymbolPeriod(ChartID(), Symbol(), GetLowerTimeFrame((ENUM_TIMEFRAMES)Period()));
191187
}
192-
else if ((MainKey_SwitchUp != 0) && (lparam == MainKey_SwitchUp)
188+
else if ((MainKey_SwitchUp != 0) && (key == MainKey_SwitchUp)
193189
&& ((((!ShiftRequired_SwitchUp) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) >= 0)) || ((ShiftRequired_SwitchUp) && (TerminalInfoInteger(TERMINAL_KEYSTATE_SHIFT) < 0))) // Shift
194190
&& (((!CtrlRequired_SwitchUp) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) >= 0)) || ((CtrlRequired_SwitchUp) && (TerminalInfoInteger(TERMINAL_KEYSTATE_CONTROL) < 0)))) // Control
195191
)
196192
{
197-
if (ArraySize(TF_Array) == 0) return;
198-
bool tf_found = false;
199-
for (int i = 0; i < ArraySize(TF_Array); i++)
193+
if (ChangeAllCharts)
200194
{
201-
if (Period() == TF_Array[i]) // Easy - the TF has been found.
195+
for (long chart = ChartFirst(); chart >= 0; chart = ChartNext(chart))
202196
{
203-
if (i < ArraySize(TF_Array) - 1) i++;
204-
else i = 0;
205-
ChartSetSymbolPeriod(ChartID(), Symbol(), TF_Array[i]);
206-
tf_found = true;
207-
break;
208-
}
209-
}
210-
if (!tf_found) // Difficult - TF not found.
211-
{
212-
// Find the first TF < current one:
213-
for (int i = ArraySize(TF_Array) - 1; i >= 0 ; i--)
214-
{
215-
if (PeriodSeconds() > PeriodSeconds(TF_Array[i]))
197+
if (chart != ChartID())
216198
{
217-
if (i < ArraySize(TF_Array) - 1) i++;
218-
else i = 0;
219-
ChartSetSymbolPeriod(ChartID(), Symbol(), TF_Array[i]);
220-
tf_found = true;
221-
break;
199+
ChartSetSymbolPeriod(chart, ChartSymbol(chart), GetUpperTimeFrame(ChartPeriod(chart)));
222200
}
223201
}
224-
if (!tf_found) // If once again not found - i.e., all TFs are above the current one:
225-
{
226-
// Switch to the first one.
227-
ChartSetSymbolPeriod(ChartID(), Symbol(), TF_Array[0]);
228-
}
229202
}
203+
ChartSetSymbolPeriod(ChartID(), Symbol(), GetUpperTimeFrame((ENUM_TIMEFRAMES)Period()));
230204
}
231205
}
232206

@@ -248,13 +222,19 @@ void DissectHotKeyCombination(const string hotkey, bool &shift_required, bool &c
248222
else if (keys[i] == "CTRL") ctrl_required = true;
249223
}
250224
}
251-
StringToUpper(keys[n - 1]);
252-
if (keys[n - 1] == "TAB") main_key = 9;
253-
else if ((keys[n - 1] == "ESC") || (keys[n - 1] == "ESCAPE")) main_key = 27;
254-
else if ((keys[n - 1] == "BACKSPACE") || (keys[n - 1] == "BACK") || (keys[n - 1] == "BS") || (keys[n - 1] == "BKSP")) main_key = 8;
255-
else if ((keys[n - 1] == "CAPS") || (keys[n - 1] == "CAPS LOCK") || (keys[n - 1] == "CAPSLOCK") || (keys[n - 1] == "CAPSLK")) main_key = 20;
225+
StringToLower(keys[n - 1]);
226+
StringReplace(keys[n - 1], " ", ""); // Remove spaces.
227+
if (keys[n - 1] == "tab") main_key = 9;
228+
else if ((keys[n - 1] == "esc") || (keys[n - 1] == "escape")) main_key = 27;
229+
else if ((keys[n - 1] == "backspace") || (keys[n - 1] == "back") || (keys[n - 1] == "bs") || (keys[n - 1] == "bksp")) main_key = 8;
230+
else if ((keys[n - 1] == "caps") || (keys[n - 1] == "capslock") || (keys[n - 1] == "capslk")) main_key = 20;
231+
else if ((keys[n - 1] == "uparrow") || (keys[n - 1] == "arrowup")) main_key = 38;
232+
else if ((keys[n - 1] == "downarrow") || (keys[n - 1] == "arrowdown") || (keys[n - 1] == "arrowdn") || (keys[n - 1] == "dnarrow")) main_key = 40;
233+
else if ((keys[n - 1] == "leftarrow") || (keys[n - 1] == "arrowleft")) main_key = 37;
234+
else if ((keys[n - 1] == "rightarrow") || (keys[n - 1] == "arrowright")) main_key = 39;
235+
else if ((keys[n - 1] == "pageup") || (keys[n - 1] == "pgup")) main_key = 33;
236+
else if ((keys[n - 1] == "pagedown") || (keys[n - 1] == "pgdown") || (keys[n - 1] == "pagedn") || (keys[n - 1] == "pgdn")) main_key = 34;
256237
else main_key = (uchar)StringGetCharacter(keys[n - 1], 0);
257-
if (main_key == 96) main_key = 192; // A hack to use ` as a hotkey.
258238
}
259239

260240
void PrepareSwitchThroughArray()
@@ -297,4 +277,88 @@ ENUM_TIMEFRAMES StringToTimeframe(string s)
297277
if ((s == "M1") || (s == "1M") || (s == "PERIOD_M1")) return PERIOD_M1;
298278
return PERIOD_CURRENT;
299279
}
280+
281+
void ChangeToSpecificTimeFrame(ENUM_TIMEFRAMES tf)
282+
{
283+
if (ChangeAllCharts)
284+
{
285+
for (long chart = ChartFirst(); chart >= 0; chart = ChartNext(chart))
286+
{
287+
if (chart != ChartID())
288+
{
289+
ChartSetSymbolPeriod(chart, ChartSymbol(chart), tf);
290+
}
291+
}
292+
}
293+
ChartSetSymbolPeriod(ChartID(), Symbol(), tf);
294+
}
295+
296+
ENUM_TIMEFRAMES GetLowerTimeFrame(ENUM_TIMEFRAMES current_tf)
297+
{
298+
if (ArraySize(TF_Array) == 0) return current_tf;
299+
for (int i = 0; i < ArraySize(TF_Array); i++)
300+
{
301+
if (current_tf == TF_Array[i]) // Easy - the TF has been found.
302+
{
303+
if (i > 0) i--;
304+
else i = ArraySize(TF_Array) - 1;
305+
return TF_Array[i];
306+
}
307+
}
308+
// Find the first TF > current one:
309+
for (int i = 0; i < ArraySize(TF_Array); i++)
310+
{
311+
if (PeriodSeconds(current_tf) < PeriodSeconds(TF_Array[i]))
312+
{
313+
if (i > 0) i--;
314+
else i = ArraySize(TF_Array) - 1;
315+
return TF_Array[i];
316+
}
317+
}
318+
// Return the last one in the array.
319+
return TF_Array[ArraySize(TF_Array) - 1];
320+
}
321+
322+
ENUM_TIMEFRAMES GetUpperTimeFrame(ENUM_TIMEFRAMES current_tf)
323+
{
324+
if (ArraySize(TF_Array) == 0) return current_tf;
325+
for (int i = 0; i < ArraySize(TF_Array); i++)
326+
{
327+
if (current_tf == TF_Array[i]) // Easy - the TF has been found.
328+
{
329+
if (i < ArraySize(TF_Array) - 1) i++;
330+
else i = 0;
331+
return TF_Array[i];
332+
}
333+
}
334+
// Find the first TF < current one:
335+
for (int i = ArraySize(TF_Array) - 1; i >= 0 ; i--)
336+
{
337+
if (PeriodSeconds(current_tf) > PeriodSeconds(TF_Array[i]))
338+
{
339+
if (i < ArraySize(TF_Array) - 1) i++;
340+
else i = 0;
341+
return TF_Array[i];
342+
}
343+
}
344+
// Return the first one in the array.
345+
return TF_Array[0];
346+
}
347+
348+
void ShowSignature()
349+
{
350+
ObjectCreate(ChartID(), "STK_Signature", OBJ_LABEL, 0, 0, 0);
351+
ObjectSetString(ChartID(), "STK_Signature", OBJPROP_TEXT, "STK");
352+
ObjectSetInteger(ChartID(), "STK_Signature", OBJPROP_CORNER, CORNER_LEFT_LOWER);
353+
ObjectSetInteger(ChartID(), "STK_Signature", OBJPROP_XDISTANCE, 3);
354+
ObjectSetInteger(ChartID(), "STK_Signature", OBJPROP_YDISTANCE, 15);
355+
ObjectSetString(ChartID(), "STK_Signature", OBJPROP_FONT, "Verdana");
356+
ObjectSetInteger(ChartID(), "STK_Signature", OBJPROP_FONTSIZE, 8);
357+
ObjectSetInteger(ChartID(), "STK_Signature", OBJPROP_COLOR, clrDarkGray);
358+
ObjectSetInteger(ChartID(), "STK_Signature", OBJPROP_SELECTABLE, false);
359+
ObjectSetInteger(ChartID(), "STK_Signature", OBJPROP_SELECTED, false);
360+
ObjectSetInteger(ChartID(), "STK_Signature", OBJPROP_HIDDEN, true);
361+
ObjectSetInteger(ChartID(), "STK_Signature", OBJPROP_BACK, true);
362+
ObjectSetString(ChartID(), "STK_Signature", OBJPROP_TOOLTIP, "Switch Timeframes Keys is running.");
363+
}
300364
//+------------------------------------------------------------------+

0 commit comments

Comments
 (0)