Zorro supports most major brokers either with a direct
connection, or by connecting through a broker-supported platform, for instance with
the MT4/5 bridge or the Sierra
bridge. A direct connection to a broker API, exchange, market data feed, or
platform is established with a DLL in Zorro's Plugin folder. Zorro
automatically scans that folder at startup, and lists all valid DLLs in the [Broker
/ Account] scrollbox. The DLL uses the broker's API for placing orders and
getting market data. The interface is organized for keeping the DLL as simple as
possible.
Only a few functions are required for basic automated trading. Additional
functionality, for instance to activate special order types or getting special data,
can be implemented with an optional broker command.
If you know programming and have access to the broker's API documentation, you can
write a broker DLL in a few hours. For downloading historical data in CSV or JSON
format from online data sources you'll need no DLL;
a small script is sufficient (see assetHistory).
Plugins can be written in any language that supports DLLs, such as Java, Pascal, C#, or C++. Many plugins have been written by Zorro users, mostly in C++. We reward proper C++ written plugins with a free Zorro S subscription, license, or update extension. As a starting point you can use the plugin for a cryptocurrency REST API, which can be found in Zorro's Source folder. The source code of other plugins developed by Zorro users is available on the GitHub pages of their authors.
An article about writing a broker plugin can be found on Financial Hacker.
The source code of included broker plugins is available on request to Zorro S users who are developing a similar plugin for the community. Please contact us with a short description of your project and your prior C++ experience. You'll need to sign a non-disclosure agreement, and send us back the final plugin with source code for review. Technical support is free for developing broker plugins; for this you'll need no support ticket or Zorro S subscription.
You can also contact us for outsourcing a plugin development.
Creating a VC++ DLL project with access to all Zorro functions is described under VC++ project setup. Zorro functions, such as for HTTP requests or signatures, are often useful for the implementation. But if you want a plain DLL with no Zorro stuff, do not bind the ZorroDll.cpp source file, but use the dllmain.cpp file that's automatically created by VC++. Its DllMain function is the main entry point of the broker DLL, and you can leave that function unchanged. Broker functions require the DATE and T6 data types, thus you need to define DATE and include the trading.h header, like this:
typedef double DATE;
#include <trading.h>
If your broker DLL accesses Zorro-specific structs, set the struct alignment to 4 with a #pragma pack(4) statement before including trading.h. Otherwise structs have different sizes in Zorro and in your DLL.
For a DLL to appear in the scrollbox, it must be located in the Plugin folder. Zorro first checks at start if the DLL can be opened with LoadLibrary(). If so, it checks if there is a BrokerOpen function (see below) and if it returns a valid version number. If both conditions are fulfilled, the DLL is registered and appears in the scrollbox. LoadLibrary will fail when DllMain does not return properly. Most frequent reasons are not creating a plain Win32 DLL (f.i. a 64-bit or MFC DLL) or a missing module that the DLL requires. Thus, the more complex libraries you're using, the more likely is your DLL to fail, probably not on your, but on other people's PCs. For being on the safe side, include in the distribution all modules that your DLLs needs. If in doubt, check your DLL's dependencies with DependencyWalker. For debugging, place breakpoints in DllMain and BrokerOpen and check what's happening when Zorro starts.
On Financial Hacker you can find a step by step instruction for implementing a REST API DLL.
The Source folder contains broker plugin examples in .zip archives:
You can find more Zorro broker plugins on Github. Use the best suited as a template for your own plugin. Implement the DLL functions (see below) in this order: BrokerOpen, BrokerLogin, BrokerAsset, BrokerBuy2. These 4 functions (described below) are the minimum required for trading with the broker. Optionally, implement BrokerAccount, BrokerHistory2, BrokerTime, BrokerTrade, BrokerSell2, BrokerStop if supported by the API. Test any function after implementation with the TradeTest script.
Some functions need not be fully implemented, or not at all. The minimum functions for TradeTest to run are BrokerOpen and BrokerLogin. If a function, f.i. BrokerAsset, is not yet available in the DLL, Zorro simulates it with default values. So you can implement and test the functions step by step.
As soon as the BrokerAsset function is correctly implemented, you should see the current price in the Server window. The TradeTest script opens a panel with the following buttons for testing various broker functions:
[Auto On/Off] - Toggle button for a simulated trade session that automatically opens or closes a trade every minute.
[NFA On/Off] - Toggle the NFA flag. Required for most US accounts; not to be set for most Forex/CFD accounts.
[Hedge] - Toggle between Hedge modes 0, 2, 4,and 5. Some brokers do not support full hedging (mode 2) or partial closing (mode 5).
[Order] - Toggle between limit (LMT), market orders (MKT), good-til-cancelled (GTC) and adaptive orders (Adaptive) when supported by the plugin.
[Asset] - Enter the asset symbol to trade (default: asset from the scroll box).
[Buy Long] - Open a long position with the Lots and Stop value set up with the sliders.
[Buy Short] - Open a short position. Dependent on Hedge, close any open position in opposite direction.
[Close Long] - Close the given number of lots from an open long position. Partial closing is not supported by some brokers.
[Close Long] - Close the given number of lots from an open short position.
[Update Stop] - Sets the Stop
of all open positions to the value (in Pips) set up with the slider. Stop adjustment
is not supported by some brokers. Due to StopFactor, the
broker stop is more distant than the real stop.
LMT orders attempt to open the position at half spread, adaptive orders at zero spread. The broker must support real limit orders for this; MT4 "pending positions" are no limit orders and will not work for LMT or adaptive orders. Various trading modes, broker commands, asset lists etc. can be set up in #define statements at the begin of the TradeTest script.
The broker DLL exports functions that are described in the following list. With VC++, exported DLL functions must be either declared with the extern "C" __declspec(dllexport) attribute, or listed in a .def file. The DLL functions use only a small subset of a usual broker API. In the following list, pointer arguments printed in italic can be NULL; if they are nonzero, the function must fill them with the required data. All data is mandatory if not mentioned otherwise.
Name | Output, char[32] array to be filled with the name of the broker, f.i. "FXCM". The name appears in the Account scrollbox adn is used for selecting the plugin. |
fpMessage | Input, pointer to a int BrokerMessage(const char* Message) function. The plugin can call BrokerMessage for printing messages - usually errors - in Zorro's message window. Using this function is not mandatory, but recommended. If the message string begins with an exclamation mark '!', Zorro opens an alert box for notifying the user that his attention might be required. If it begins with a hash '#', it is printed into the diagnostics file only. |
fpProgress | Input, pointer to a int BrokerProgress(intptr_t Progress) function. The plugin can call it repeatedly to keep Zorro responsive in long loops or when broker operations take longer than a second, like BrokerHistory2. When Progress is 0, the Zorro UI will only update its controls for preventing unresponsiveness. When it is 1, dots will be printed in the message window for indicating progress of a lengthy operation. When Progress is a pointer and a callback function exists in the script, it is called and the pointer is passed for triggering script functions from the broker API. When BrokerProgress returns 0, someone has hit Zorro's [Stop] button and the current broker operation must be aborted. |
User | Input, User name for logging in, or NULL for logging out. |
Pwd | Input, Password for logging in. |
Type | Input, account type for logging in; either "Real" or "Demo". |
Accounts | Input / optional output, char[1024] array, intially filled with the account id from the account list. Can be filled with all user's account numbers as subsequent zero-terminated strings, ending with "" for the last string. When a list is returned, the first account number is used by Zorro for subsequent BrokerAccount calls. |
pTimeUTC | Optional output, current server time in UTC / GMT+0 with no daylight saving. The DATE format (OLE date/time) is a double float value, counting days since midnight 30 December 1899, while hours, minutes, and seconds are represented as fractional days. |
DATE convertTime(__time32_t t32) { return (double)t32/(24.*60.*60.) + 25569.; // 25569. = DATE(1.1.1970 00:00)
} __time32_t convertTime(DATE date) { return (__time32_t)((date - 25569.)*24.*60.*60.);
}
Asset | Input, asset symbol for live prices (see Symbols). |
pPrice | Optional output, current ask price of the asset, or NULL for subscribing the asset. An asset must be subscribed before any information about it can be retrieved. |
pSpread | Optional output, the current difference of ask and bid price of the asset. |
pVolume | Optional output, a parameter reflecting the current supply and demand of the asset. Such as trade volume per minute, accumulated daily trade volume, open interest, ask/bid volume, or tick frequency. If a value is returned, it should be consistent with the fVol content of the T6 struct in BrokerHistory2 (see below).. |
pPip | Optional output, size of 1 PIP, f.i. 0.0001 for EUR/USD. |
pPipCost | Optional output, cost of 1 PIP profit or loss per lot, in units of the account currency. If not directly supported, calculate it as decribed under asset list. |
pLotAmount | Optional output, minimum order size, i.e. number of contracts for 1 lot of the asset. For currencies it's usually 10000 with mini lot accounts and 1000 with micro lot accounts. For CFDs it's usually 1, but can also be a fraction of a contract, like 0.1. |
pMargin | Optional output, either initial margin cost for buying 1 lot of the asset in units of the account currency. Or the leverage of the asset when negative (f.i. -50 for 50:1 leverage). |
pRollLong | Optional output, rollover fee for long trades, i.e. interest that is added to or subtracted from the account for holding positions overnight. The returned value is the daily fee per 10,000 contracts for currencies, and per contract for all other assets, in units of the account currency. |
pRollShort | Optional output, rollover fee for short trades. |
pCommission | Optional output, roundturn commission per 10,000 contracts for currencies, per contract for all other assets, in units of the account currency. |
double Price = MarketInfo(Asset,MODE_ASK);
double Spread = Price - MarketInfo(Asset,MODE_BID);
double Volume = 0;
double LotFactor = MarketInfo(Asset,MODE_MINLOT); // correction for different lot scale
double Pip = MarketInfo(Asset,MODE_POINT);
double PipCost = MarketInfo(Asset,MODE_TICKVALUE) * LotFactor;
int DigitSize = MarketInfo(Asset,MODE_DIGITS); // correction for brokers with 5 digits if(DigitSize == 3 || DigitSize == 5) { Pip *= 10.;
PipCost *= 10.; }
double MinAmount = MarketInfo(Asset,MODE_LOTSIZE) * LotFactor;
double Margin = MarketInfo(Asset,MODE_MARGINREQUIRED) * LotFactor; double RollLong = MarketInfo(Asset,MODE_SWAPLONG); double RollShort = MarketInfo(Asset,MODE_SWAPSHORT);
if(MarketInfo(Asset,MODE_SWAPTYPE) == 0.) { RollLong *= PipCost; RollShort *= PipCost; }
Asset | Input, asset symbol for historical prices (see Symbols). |
tStart | Input, UTC start date/time of the price history (see BrokerTime about the DATE format). This has only the meaning of a seek-no-further date; the relevant date for the begin of the history is tEnd. |
tEnd | Input, UTC end date/time of the price history. If the price history is not available in UTC time, but in the brokers's local time, the plugin must convert it to UTC. |
nTickMinutes | Input, time period of a tick in minutes. Usual values are 0 for single ticks (for T1 or T2 data; all prices of a T6 struct get the tick price), 1 for one-minute (M1) historical candles, or a larger value for low-resolution data. |
nTicks | Input, maximum number of ticks to be filled; must not exceed the number returned by brokerCommand(GET_MAXTICKS,0), or 300 otherwise. |
ticks | Output, array of T6 structs (defined in include\trading.h) to be filled with the ask prices, close time, and additional data if available, such as historical spread and volume. See history for details. The ticks array is filled in reverse order from tEnd on until either the tick time reaches tStart or the number of ticks reaches nTicks, whichever happens first. The most recent tick, closest to tEnd, is at the start of the array. In the case of T1 or T2 data, or when only a single price is available, all prices in a T6 struct must be set to the same value. |
Account | Input, new account name or number, or NULL for using the current account. |
pBalance | Optional output, current balance on the account. |
pTradeVal | Optional output, current value of all open trades; the difference between account equity and returned balance value. If not available, Zorro estimes the equity from balance and value of all open trades. If no balance was returned, the account equity can be returned in pTradeVal. |
pMarginVal | Optional output, current total margin bound by all open trades. If not |
Asset | Input, asset symbol for trading (see Symbols). |
Amount | Input, number of units, positive for a long trade and negative for a short trade. For currencies or CFDs, the number of units is the number of Lots multiplied with the LotAmount. If LotAmount is < 1 (f.i. for a CFD, or for a fractional share with 0.1 contracts lot size), the number of lots is given here instead of the number of units. |
StopDist | Optional input, 'safety net' stop loss distance to the opening price when StopFactor was set, or 0 for no stop, or -1 for indicating that this function was called for closing a position. This is not the real stop loss, which is handled by Zorro. Can be ignored if the API is NFA compliant and does not support a stop loss in a buy/sell order. |
Limit | Optional input, fill price for limit orders, set up by OrderLimit, or 0 for market orders. Can be ignored if limit orders are not supported by the API. |
pPrice | Optional output, the average fill price if the position was partially or fully filled. If no price was set, Zorro assumes the current price. |
pFill | Optional output, the fill amount (positive), or 0 for an unfilled order. If no amount was set, Zorro assumes a complete fill. |
nTradeID | Input, order/trade ID as returned by BrokerBuy, or -1 when the trade UUID was set before with a SET_UUID command. |
pOpen | Optional output, the average fill price if the trade was partially or fully filled. If not available by the API, Zorro will estimate the values based on last price and asset parameters. |
pClose | Optional output, current bid or ask close price of the trade. If not available, Zorro will estimale the value based on current ask price and ask-bid spread. |
pCost | Optional output, total rollover fee (swap fee) of the trade so far. If not available, Zorro will estimate the swap from the asset parameters. |
pProfit | Optional output, current profit or loss of the trade in account currency units, without rollover and commission. If not available, Zorro will estimate the profit from the difference of current price and fill price. |
nTradeID | Input, trade/order ID as returned by BrokerBuy2, or -1 for a UUID to be set before with a SET_UUID command. |
nAmount | Input, number of contracts resp. lots to be closed, positive for a long trade and negative for a short trade (see BrokerBuy). If less than the original size of the trade, the trade is partially closed. |
Limit | Optional input, fill price for a limit order, set up by OrderLimit, or 0 for closing at market. Can be ignored if limit orders are not supported by the API. |
pClose | Optional output, close price of the trade. |
pCost | Optional output, total rollover fee (swap fee) of the trade. |
pProfit | Optional output, total profit or loss of the trade in account currency units. |
pFill | Optional output, the amount that was closed from the position, always positive. |