This a server plugin for MetaTrader 4 to calculate and pay commissions at real time. In addition, it can calculate rebate to pay back to client if lead decided to divide bonus fee with his client. It is ready to work with WebAPI through MetaQuotes Manager API.
Installation #
To deploy the plugin you have to put .dll and .lic files under /plugins/ folder of your MT4 server installation folder
Settings #
In general, settings file should be in this format:
CPlugin.IBCommissions.ini
guid=<guid> shares=<shares> clients count=<number of clients> client<client index>=<client login> <agent login> commissions count=<number of commissions> commission<commission index>=<group> <symbol> <amount> <numerator> <denominator> rebates count=<number of rebates> rebate<rebate index>=<rebate client login> <rebate percent> verbose=<verbose> |
Common settings
guid is a unique GUID that be generated automatically when you first run server with the plugin. After you can change it if you need. It is for correlation when you use WebAPI to be sure that exact this plugin instance catch a request.
verbose - verbosity of logging, 0 for errors and warnings, 1 for 0 plus common info and settings, 2 for debugging
shares - a list of numbers separated by empty space. Each number is a percent that needs to share bonuses within multi-level IB tree. By default, it is 20. First level is always 100%. Last number will be default value for deeper levels.
For example, we have shares=20 10
.
And we have a tree: client > SubIB_Level3 > SubIB_Level2 > SubIB_Level1 > MasterIB. We’d like to pay $5.
SubIB_Level3 claims for $5 and must share 20% of $5 with SubIB_Level2.
Therefore, he gets $5 - $5 20% = $5 - $1 = $4
SubIB_Level2 claims for $1 and must share 10% of $1 with SubIB_Level1.
Therefore, he gets $1 - $1 10% = $1 - $0.1 = $0.9
SubIB_Level1 claims for $0.1 and must share 10% of $0.1 with MasterIB.
Therefore, he gets $0.1 - $0.1 * 10% = $0.1 - $0.01 = $0.09
MasterIB will get $0.01
Sum is always $5
Clients configuration #
number of clients - number of records below to define rebates
client index must be between 1 and <number of clients> with no gaps
client login - an account who trade
agent login - an IB who receive commissions
Commissions rules #
number of commissions - number of records below to define commission rules.
commission index - must be between 1 and <number of commissions> with no gaps.
group - client’s group name mask, for instance demo or demoforex or demo.
symbol - symbol name mask or symbol security group mask, for instance: EURUSD or EUR* or Metals.
amount - an amount we pay, depends on <numerator> and <denominator>.
numerator - what we pay: 1 for money (USD by default), 2 for pips
denominator - for what we pay: 1 for each closed lot, 2 for each closed deal
When plugin calculate commission, it uses algorithm to pay <numerator> as amount per <denominator> as a volume traded. Like MT4 does.
Therefore, you might choose one of these algorithms:
$/lot
$/deal
pips/lot
pips/deal
Example:
commission1=demo EUR* 5 1 1
All groups starting from demo.
All symbols contained EUR in their names.
We pay $5 per each closed Lot.
Rebates for clients #
number of rebates - number of records below to define rebates.
rebate index must be between 1 and <number of rebates> with no gaps.
rebate client login - login of client who receive a piece of bonus that his IB got.
rebate percent - the percent. Plugin will deduct rebate from master payment to IB.
For example, a client trades. An IB is going to get $1.00 of commission and he decided to pay 10% back to his client. Therefore, IB will get $0.9 and $0.1. They will get $1.00 in total.
Real life settings file example with MT4 log
For example we have this scheme:
‘100’ is MasterIB
‘101’ is SubIB of ‘100’
‘102’ is SubIB of ‘101’
‘1000’ is a client of ‘102’
‘102’ decides to pay back to his client 10% of his bonus
CPlugin.IBCommissions.ini file below:
guid=da7ededa-28dd-4b4f-9ed9-db219710422e
verbose=2
shares=20
clients count=3
client1=1000 102
client2=102 101
client3=101 100
commissions count=1
commission1=demoforex * 5 1 1
rebates count=1
rebate1=1000 10
So, lets show what happen after ‘1000’ close one lot.
For each lot closed by client broker pays $5, so MasterIB, SubIBs and Client will share $5 between all.
If we have only one level tree, MasterIB would get all amount.
Using sharing parameter, we have to transfer 20% of $5 from ‘102’ to ‘101’. Furthermore, ‘101’ will transfer 20% of his bonus to ‘100’.
In addition, ‘102’ decided to pay back 10% of his bonus back to client. Therefore, we get 10% from $4 that is $0.4 and pay to client. After that, ‘102’ will get only $3.6.
$1 (that we send to ‘101’) must be shared between ‘101’ and ‘100’, so, we transfer 20% of $1 to ‘100’.
MT4 proves it
0 16:13:41 222.222.0.1 '1': request from '1000' (buy 1.00 EURUSD at 1.11751 sl: 0.00000 tp: 0.00000)
0 16:13:41 222.222.0.1 '1': confirm '1000' buy 1.00 EURUSD at 1.11751 sl: 0.00000 tp: 0.00000 (1.11707 / 1.11725)
1 16:13:41 127.0.0.1 '1000': order #503723575, buy 1.00 EURUSD at 1.11751
... after a while…
1 16:13:43 127.0.0.1 '1000': close instant order #503723575 buy 1.00 EURUSD at 1.11712 sl: 0.00000 tp: 0.00000 (1.11712 / 1.11730)
0 16:13:43 222.222.0.1 '1': request from '1000' (close #503723575 buy 1.00 EURUSD at 1.11712)
0 16:13:43 222.222.0.1 '1': confirm '1000' close #503723575 buy 1.00 EURUSD at 1.11712 (1.11710 / 1.11729)
0 16:14:17 222.222.0.1 '1': dealer disconnected
2 16:14:46 222.222.0.1 '1': login (4.00 482, manager, 0)
0 16:14:46 CPlugin.IBCommissions commission[1] #503723576 3.60 USD credited to '102'
0 16:14:46 CPlugin.IBCommissions rebate #503723577 0.40 USD credited to '1000'
0 16:14:46 CPlugin.IBCommissions commission[1] #503723578 0.80 USD credited to '101'
0 16:14:46 CPlugin.IBCommissions commission[1] #503723579 0.20 USD credited to '100'
WebAPI integration #
It catches MT4ServerAPI::ExternalCommand hook to answer on WebAPI requests.
All you need to work with the plugin is to send any of Request described below. It sends you back an answer or nothing, depends.
C++ enums and DTOs
#pragma pack(push, 1)
struct RequestCommonHeader
{
GUID guid;
int cmdCode;
};
enum CommandCodes
{
BASE,
Rebates_GetAll,
Rebates_Clear,
Rebates_Get,
Rebates_Set,
Commissions_GetAll,
Commissions_Clear,
Commissions_Get,
Commissions_Set,
Links_GetAll,
Links_Clear,
Links_Get,
Links_Set,
Links_GetIB,
};
struct RebateDTO
{
int client;
double percent;
};
struct CommissionDTO
{
char group[128];
char symbol[128];
double value;
int numerator;
int denominator;
};
struct LinkDTO
{
int client;
int ib;
};
#pragma pack(pop)
Common structures
#pragma pack(push, 1)
struct RequestCommonHeader
{
GUID guid;
int commandCode;
};
struct ResponseVoid
{
};
template<typename T>
struct Response
{
const BYTE ff; // it is always 0xff
T data;
};
template<typename T>
struct ResponseArray
{
const BYTE ff; // it is always 0xff
int total;
T data[];
};
#pragma pack(pop)
Structures to pass into ExternalCommand for each request type
#pragma pack(push, 1)
struct Request_Base : RequestCommonHeader { };
// response: ResponseVoid
struct Request_Rebates_GetAll : RequestCommonHeader { };
// response: ResponseArray<RebateDTO>
struct Request_Rebates_Clear : RequestCommonHeader { };
// response: ResponseVoid
struct Request_Rebates_Get : RequestCommonHeader { int login; };
// response: RebateDTO
struct Request_Rebates_Set : RequestCommonHeader { RebateDTO rebate; };
// response: ResponseVoid
struct Request_Commissions_GetAll : RequestCommonHeader { };
// response: ResponseArray<CommissionDTO>
struct Request_Commissions_Clear : RequestCommonHeader { };
// response: ResponseVoid
struct Request_Commissions_Get : RequestCommonHeader { int idx; };
// response: CommissionDTO
struct Request_Commissions_Set : RequestCommonHeader { int idx; CommissionDTO data; };
// response: ResponseVoid
struct Request_Links_GetAll : RequestCommonHeader { };
// response: ResponseArray<LinkDTO>
struct Request_Links_Clear : RequestCommonHeader { };
// response: ResponseVoid
struct Request_Links_Get : RequestCommonHeader { int login; };
// response: LinkDTO
struct Request_Links_Set : RequestCommonHeader { LinkDTO link; };
// response: ResponseVoid
struct Request_Links_GetIB : RequestCommonHeader { int login; };
// response: ResponseArray<int>
#pragma pack(pop)