Initial commit: MQL5 Scripts Collection (MetaTrader 5)
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
# 🚀 Unlock the Power of Trading!
|
||||
|
||||
Welcome to this open-source trading project. Here you will find powerful tools to enhance your trading journey. If you find this project useful, please consider starring ⭐, sharing, or donating to support further development!
|
||||
|
||||
---
|
||||
|
||||
**Support the project:**
|
||||
- Star this repository on GitHub
|
||||
- Share it with your trading friends
|
||||
- [Donate here](https://www.paypal.com/donate/?hosted_button_id=YOUR_BUTTON_ID) to help us grow!
|
||||
|
||||
---
|
||||

|
||||

|
||||
|
||||
## Source Files
|
||||
- `swapmonitor.mq5`
|
||||
|
||||
---
|
||||
> Made with ❤️ for the trading community.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 126 KiB |
@@ -0,0 +1,292 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| SwapMonitor.mq5 |
|
||||
//| Copyright (c) 2024, Marketeer |
|
||||
//| https://www.mql5.com/en/users/marketeer |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#property service
|
||||
#property copyright "Copyright (c) 2024 Marketeer"
|
||||
#property link "https://www.mql5.com/en/users/marketeer"
|
||||
#property version "1.0"
|
||||
#property script_show_inputs
|
||||
|
||||
#include <MQL5Book/ArrayUtils.mqh>
|
||||
#include <MQL5Book/Defines.mqh>
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| I N P U T S |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
input string SymbolList = ""; // SymbolList (comma,separated)
|
||||
input string Folder = "Swaps";
|
||||
input uint Beat = 10; // Beat (seconds)
|
||||
input bool AutoSelect = false;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Global definitions |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
const string Program = EnumToString((ENUM_PROGRAM_TYPE)MQLInfoInteger(MQL_PROGRAM_TYPE)) + " " + MQLInfoString(MQL_PROGRAM_NAME);
|
||||
|
||||
string SymbolArray[];
|
||||
|
||||
struct Swaps // could be null-ed on creation by compiler if static and global (not the case)
|
||||
{
|
||||
datetime dt;
|
||||
double L;
|
||||
double S;
|
||||
int N;
|
||||
|
||||
Swaps()
|
||||
{
|
||||
ZeroMemory(this);
|
||||
}
|
||||
|
||||
Swaps(const datetime t, const double l, const double s, const int n = 0): dt(t), L(l), S(s), N(n) { }
|
||||
|
||||
string csv() const
|
||||
{
|
||||
return StringFormat("%s,%g,%g", TimeToString(dt, TIME_DATE | TIME_SECONDS), L, S);
|
||||
}
|
||||
};
|
||||
|
||||
struct Position
|
||||
{
|
||||
ulong ticket;
|
||||
double swap;
|
||||
};
|
||||
|
||||
Swaps cache[];
|
||||
Position positions[];
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Service program start function |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
void OnStart()
|
||||
{
|
||||
if(StringSplit(SymbolList, ',', SymbolArray) < 1)
|
||||
{
|
||||
Print("No symbols given");
|
||||
if(AutoSelect)
|
||||
{
|
||||
for(int i = 0; i < SymbolsTotal(true); i++)
|
||||
{
|
||||
const string symbol = SymbolName(i, true);
|
||||
if(!SymbolInfoInteger(symbol, SYMBOL_CUSTOM)
|
||||
&& SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE) != SYMBOL_TRADE_MODE_DISABLED)
|
||||
{
|
||||
PUSH(SymbolArray, symbol);
|
||||
}
|
||||
}
|
||||
Print("MarketWatch symbols autoselected:");
|
||||
ArrayPrint(SymbolArray);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < ArraySize(SymbolArray); i++)
|
||||
{
|
||||
if(!SymbolInfoInteger(SymbolArray[i], SYMBOL_EXIST))
|
||||
{
|
||||
Print("Unknown symbol: ", SymbolArray[i]);
|
||||
SymbolArray[i] = "";
|
||||
}
|
||||
else if(!SymbolInfoInteger(SymbolArray[i], SYMBOL_VISIBLE))
|
||||
{
|
||||
if(AutoSelect && SymbolSelect(SymbolArray[i], true))
|
||||
{
|
||||
// ok
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintFormat("Can't select symbol: %s [%d]", SymbolArray[i], _LastError);
|
||||
SymbolArray[i] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArrayPurge(SymbolArray, "");
|
||||
ArrayResize(cache, ArraySize(SymbolArray));
|
||||
|
||||
Print(Program + " started");
|
||||
bool active = true;
|
||||
|
||||
for(; !IsStopped() ;)
|
||||
{
|
||||
// wait for connected and logged in state
|
||||
if(!(TerminalInfoInteger(TERMINAL_CONNECTED) && AccountInfoInteger(ACCOUNT_LOGIN)))
|
||||
{
|
||||
if(active)
|
||||
{
|
||||
Print(Program + " is waiting for connection");
|
||||
active = false;
|
||||
}
|
||||
|
||||
Sleep(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!active)
|
||||
{
|
||||
Print(Program + " connected");
|
||||
active = true;
|
||||
}
|
||||
|
||||
// check swaps in symbols properties and save changes (if any)
|
||||
const string filename = GetTimeStamp();
|
||||
for(int i = 0; i < ArraySize(SymbolArray); i++)
|
||||
{
|
||||
if(StringLen(SymbolArray[i]) && !SaveSymbolSwap(SymbolArray[i], filename, cache[i]))
|
||||
{
|
||||
SymbolArray[i] = "";
|
||||
}
|
||||
}
|
||||
|
||||
// check if positions still exist
|
||||
for(int i = 0; i < ArraySize(positions); i++)
|
||||
{
|
||||
if(!PositionSelectByTicket(positions[i].ticket))
|
||||
{
|
||||
Alert(StringFormat("Position %llu closed with swap %g", positions[i].ticket, positions[i].swap));
|
||||
positions[i].ticket = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayPurger<Position> purger(positions, IsClosedPosition);
|
||||
|
||||
// compare positions swaps and alert changes (if any)
|
||||
const int n = PositionsTotal();
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
const ulong ticket = PositionGetTicket(i);
|
||||
if(ticket)
|
||||
{
|
||||
FindPositionSwap(ticket);
|
||||
}
|
||||
}
|
||||
|
||||
Sleep(Beat * 1000);
|
||||
}
|
||||
Print(Program + " stopped");
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Auxiliary functions |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
string GetTimeStamp()
|
||||
{
|
||||
MqlDateTime dt;
|
||||
TimeToStruct(TimeCurrent(), dt);
|
||||
return StringFormat("%04d%02d", dt.year, dt.mon) + ".csv";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Contains(const T &a[], const T v)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(a); i++)
|
||||
{
|
||||
if(a[i] == v) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string Escape(const string s)
|
||||
{
|
||||
uchar a[];
|
||||
uchar forbidden[] = {'<', '>', '/', '\\', '"', ':', '|', '*', '?'};
|
||||
int n = StringToCharArray(s, a);
|
||||
for(int i = 0; i < n - 1; i++)
|
||||
{
|
||||
if(a[i] < 32 || Contains(forbidden, a[i]))
|
||||
{
|
||||
a[i] = '_';
|
||||
}
|
||||
}
|
||||
return CharArrayToString(a);
|
||||
}
|
||||
|
||||
bool IsClosedPosition(const Position &p)
|
||||
{
|
||||
return !p.ticket;
|
||||
}
|
||||
|
||||
void FindPositionSwap(const ulong ticket)
|
||||
{
|
||||
const double swap = PositionGetDouble(POSITION_SWAP);
|
||||
const double volume = PositionGetDouble(POSITION_VOLUME);
|
||||
const string symbol = PositionGetString(POSITION_SYMBOL);
|
||||
const int digits = (int)MathLog10(1.0 / SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP));
|
||||
const string type = PositionGetInteger(POSITION_TYPE) ? "Sell" : "Buy";
|
||||
|
||||
for(int i = 0; i < ArraySize(positions); i++)
|
||||
{
|
||||
if(positions[i].ticket == ticket)
|
||||
{
|
||||
if(positions[i].swap != swap)
|
||||
{
|
||||
Alert(StringFormat("Position %llu (%s %.*f %s) swap: %g -> %g",
|
||||
ticket, type, digits, volume, symbol, positions[i].swap, swap));
|
||||
positions[i].swap = swap;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Position p = {ticket, swap};
|
||||
PUSH(positions, p);
|
||||
Alert(StringFormat("New position %llu (%s %.*f %s) swap: %g",
|
||||
ticket, type, digits, volume, symbol, swap));
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Persistent storage (CSV-files) |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
bool SaveSymbolSwap(const string &s, const string &f, Swaps &last)
|
||||
{
|
||||
const Swaps now
|
||||
(
|
||||
TimeCurrent(),
|
||||
SymbolInfoDouble(s, SYMBOL_SWAP_LONG),
|
||||
SymbolInfoDouble(s, SYMBOL_SWAP_SHORT),
|
||||
last.N
|
||||
);
|
||||
|
||||
if(now.L == last.L && now.S == last.S) return true; // up to date
|
||||
|
||||
const string name = Folder + "/" + Escape(s) + "/" + f;
|
||||
int h = FileOpen(name, FILE_ANSI | FILE_TXT | FILE_READ | FILE_WRITE, ",", CP_UTF8);
|
||||
if(h == INVALID_HANDLE)
|
||||
{
|
||||
PrintFormat("Can't open file '%s' [%d]", name, _LastError);
|
||||
return false;
|
||||
}
|
||||
if(!FileSize(h))
|
||||
{
|
||||
FileWrite(h, "T,L,S");
|
||||
}
|
||||
else
|
||||
{
|
||||
FileSeek(h, 0, SEEK_END);
|
||||
}
|
||||
|
||||
FileWrite(h, now.csv());
|
||||
|
||||
FileClose(h);
|
||||
|
||||
PrintFormat("%s swap changed %d-th time", s, last.N + 1);
|
||||
if(last.dt)
|
||||
{
|
||||
PrintFormat("- Old: %s L=%g S=%g", TimeToString(last.dt, TIME_DATE | TIME_SECONDS), last.L, last.S);
|
||||
}
|
||||
PrintFormat("+ New: %s L=%g S=%g", TimeToString(now.dt, TIME_DATE | TIME_SECONDS), now.L, now.S);
|
||||
Alert(StringFormat("%s swaps: L=%g S=%g", s, now.L, now.S));
|
||||
|
||||
last = now;
|
||||
last.N++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user