Multi-Tier IB
This is a server plugin for MetaTrader 4 that calculates and pays commissions in real time. It can also calculate a rebate to pay back to the client when an agent decides to share part of the bonus fee. It is ready to work with the WebAPI through the MetaQuotes Manager API.
Installation
Deploy the plugin by placing the .dll and .lic files under the /plugins/ folder of your MT4 server installation directory.
Settings
In general, the settings file should follow 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— a unique GUID that is generated automatically the first time you run the server with the plugin. You can change it afterwards if needed. It is used for correlation when you call the WebAPI, so this exact plugin instance picks up the request.verbose— logging verbosity:0for errors and warnings,1for0plus common info and settings,2for debugging.shares— a list of numbers separated by spaces. Each number is the percentage shared with the next level up within the multi-level IB tree. The default is20. The first level is always 100%. The last number is used as the default for any deeper levels.
For example, suppose shares=20 10 and we have the tree client > SubIB_Level3 > SubIB_Level2 > SubIB_Level1 > MasterIB, and we want to pay $5:
SubIB_Level3claims $5 and must share 20% of $5 withSubIB_Level2. Therefore he gets$5 - 20% of $5 = $5 - $1 = $4.SubIB_Level2claims $1 and must share 10% of $1 withSubIB_Level1. Therefore he gets$1 - 10% of $1 = $1 - $0.1 = $0.9.SubIB_Level1claims $0.1 and must share 10% of $0.1 withMasterIB. Therefore he gets$0.1 - 10% of $0.1 = $0.1 - $0.01 = $0.09.MasterIBgets $0.01.
The sum is always $5.
Clients configuration
clients count— the number of records below that define the client-to-agent links.client<index>— the index must be between 1 and<number of clients>with no gaps.client login— the account that trades.agent login— the IB who receives the commissions.
Commissions rules
commissions count— the number of records below that define commission rules.commission<index>— the index must be between 1 and<number of commissions>with no gaps.group— the client's group name mask, for instancedemo,demoforexordemo.symbol— the symbol name mask or symbol security group mask, for instanceEURUSD,EUR*orMetals.amount— the amount paid, interpreted according to<numerator>and<denominator>.numerator— what is paid:1for money (USD by default),2for pips.denominator— what it is paid for:1for each closed lot,2for each closed deal.
When the plugin calculates a commission, it pays <numerator> as the amount per <denominator> as the volume traded, just as MT4 does.
You can therefore choose one of these algorithms:
$/lot$/dealpips/lotpips/deal
Example:
commission1=demo EUR* 5 1 1
- All groups starting with
demo. - All symbols containing
EURin their names. - We pay $5 per each closed lot.
Rebates for clients
rebates count— the number of records below that define rebates.rebate<index>— the index must be between 1 and<number of rebates>with no gaps.rebate client login— the login of the client who receives a piece of the bonus that his IB got.rebate percent— the percentage. The plugin deducts the rebate from the master payment to the IB.
For example, a client trades. An IB is going to receive $1.00 of commission and decides to pay 10% back to the client. Therefore the IB gets $0.9 and the client gets $0.1 — $1.00 in total.
Real-life settings file example with MT4 log
Suppose we have this scheme:
100is the MasterIB.101is a SubIB of100.102is a SubIB of101.1000is a client of102.102decides to pay back 10% of his bonus to his client.
The CPlugin.IBCommissions.ini file:
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
Let us walk through what happens after 1000 closes one lot.
For each lot closed by the client the broker pays $5, so the MasterIB, the SubIBs and the client share that $5 between them. With a single-level tree the MasterIB would get the whole amount. Using the sharing parameter, we transfer 20% of $5 from 102 to 101, and 101 in turn transfers 20% of his bonus to 100. In addition, 102 decided to pay back 10% of his bonus to the client. Therefore we take 10% of $4, which is $0.4, and pay it to the client; after that 102 keeps only $3.6. The $1 sent to 101 must be shared between 101 and 100, so we transfer 20% of $1 to 100.
The MT4 log confirms 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 #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 #503723578 0.80 USD credited to '101'
0 16:14:46 CPlugin.IBCommissions commission #503723579 0.20 USD credited to '100'
WebAPI integration
The plugin hooks MT4ServerAPI::ExternalCommand to answer WebAPI requests. To work with it, send any of the requests described below; it sends back a response or nothing, depending on the request.
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;
char symbol;
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)

