Zorro supports most major brokers either with a direct connection, or by connecting through a platform, for instance with the MT4/5 bridge or the Sierra bridge. A 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. If you know programming, you can write a broker DLL in a few days. 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++. We reward proper C++ written plugins with a free Zorro S subscription, license, or update extension. Open source plugin code can be found in Zorro's Source folder and on the GitHub pages of plugins developed by Zorro users.
The source code of the included broker plugins is available on request to experienced programmers 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 for broker plugins is free; for this you'll need no support ticket or Zorro S subscription.
In the following you'll find instructions about how to set up Microsoft VC++ to write a broker plugin DLL for the Zorro broker API interface. The dialogs are slightly different for any VC++ version, but here's the general setup for a Win32 DLL. Create a new project (File->New Project). Select Win32 Project. When the Win32 Application Wizard pops up, select DLL in the application settings, then click [Finish]. Under VC++ 2017, select Windows Universal, then DLL. VC++ now creates a new DLL project for you, with a main cpp file that looks like this:
// Defines the entry point for the DLL application. #include "stdafx.h" BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; }
DllMain is the main entry point of the broker DLL, and you can leave that function unchanged. The 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 "whereever_you_installed_it\Zorro\include\trading.h"
If you want to distribute your broker DLL to other people, we suggest that you open Properties / C/C++ / Code Generation, and change the Runtime Library setting from Multi-threaded DLL (/MD) to Multi-threaded (/MT). Otherwise users won't be able to use the DLL without installing the VC++ Runtime Redistributable before - one of the funny ideas by Microsoft to make Windows user's life more interesting.
If your broker DLL accesses Zorro-specific structs, set struct alignment to 4, or use the #pragma pack(4) statement. Otherwise structs can have different sizes in lite-C and in VC++.
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.
The Source folder contains two 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. |
fpError | Input, pointer to a int BrokerError(const char* message) function, to be called for printing broker messages (usually error messages) in Zorro's message window. Calling this function is not mandatory. 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(DWORD progress) function, to be called repeatedly when broker operations take longer than a second, f.i. BrokerLogin or BrokerHistory. When progress is 0, the Zorro UI will update for for preventing unresponsiveness. When it is 1, dots will be printed in the message window for indicating the progress of the 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 the function returns 0, the current broker operation must be aborted. |
fpSend, fpStatus, fpResult, fpFree | Input, pointers to the http_send, http_status, http_result and http_free functions. |
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 | Optional output, char[1024] array to be filled with all user's account numbers as subsequent zero-terminated strings, ending with "" for the last string. Only the first account number is used by Zorro. |
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, f.i. trade volume per minute, open interest, quote volume, or tick frequency, when such information is available. 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, f.i. 0.1. |
pMarginCost | Optional output, initial margin cost for buying 1 lot of the asset in units of the account currency. Alternatively, the leverage of the asset when negative (f.i. -50 for 50:1 leverage). If not supported, calculate it as decribed under asset list. |
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. |
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 price ticks (T1 data; optional), 1 for one-minute (M1) historical data, or a larger value for more quickly filling the LookBack period before starting a strategy. |
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 data, or when only a single price is available, all prices in a TICK struct can 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 contracts, positive for a long trade and negative for a short trade. The number of contracts is the number of Lots multiplied with the LotAmount. If LotAmount is < 1 (f.i. for a CFD with 0.1 contracts lot size), the number of lots is given here instead of the number of contracts. |
StopDist | Optional input, absolute 'safety net' stop loss distance to the opening price, or 0 for no stop. This is not the real stop loss, which is handled by the trade engine. Placing the stop is not mandatory. NFA compliant orders do not support a stop loss in the same order; in that case StopDist is 0 for opening a trade and -1 for closing a trade by opening a position in opposite direction. |
Limit | Optional input, ask/bid 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 fill price if the trade was partially or fully filled. |
pFill | Optional output, the fill amount. Needed for other order types than FOK orders and for partial fills. |
nTradeID | Input, trade ID number as returned by BrokerBuy,, or -1 for a UUID to be set before with a SET_UUID command. |
pOpen | Optional output, the average fill price if the trade was partially or fully filled. |
pClose | Optional output, current bid or ask close price of the trade. |
pCost | Optional output, total rollover fee (swap fee) of the trade so far. |
pProfit | Optional output, current profit or loss of the trade in account currency units, without rollover and commission. |
nTradeID | Input, trade ID number as returned by BrokerBuy2, or -1 for a UUID to be set before with a SET_UUID command. |
dStop | The new stop loss price. Must be by a sufficient distace (broker dependent) below the current price for a long trade, and above the current price for a short trade. |
nTradeID | Input, trade 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, ask/bid 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 fill amount. |
nCommand | Input, command from the brokerCommand list. |
dwParameter | Input, parameter or data to the command. |