The Excel RTD widget in Figaro lets you communicate with Figaro from other applications on the same computer:
Integration with Excel is only available on Windows. Communication using HTTP and websockets is available on any platform which supports Node.js (for example, Linux and macOS).
To be able to communicate with Figaro, you need to do two things:
Open the Excel RTD widget in Figaro. This doesn't have to be visible. The Excel RTD widget continues to run even if you add it to a page in Figaro and then move to a different page.
Install the Excel RTD Bridge. This can be downloaded from https://www.fxblue.com/figaro/excel-rtd/excel-rtd-bridge
For security, you cannot execute trading actions through the Excel RTD unless you turn on the setting "Accept trading commands" in the widget.
The widget displays a "channel" setting, which defaults to your trading account number. You need this value in order to make connections, and you can change it to any other setting which you want.
Once the Excel RTD widget is running, you can use the following formula in Excel to insert a real-time feed of account, ticket, or price data. You simply need to fill in the "channel" from the widget, and the "property" which you want to display:
=RTD("FXBlueLabs.ExcelRTD", , "channel", "property")
For example, if your channel is 156734 and you want to display the account's balance, or the bid price of GBPUSD:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "balance")
=RTD("FXBlueLabs.ExcelRTD", , "156734", "bidGBPUSD")
Please note: with some language settings - for example, Polish - Excel may want the sections of the formula to be separated by semi-colons instead of commas. For example:
=RTD("FXBlueLabs.ExcelRTD"; ; "channel"; "property")
The RTD app supplies data about the account (e.g. equity and balance), symbol prices, "tickets", bar history, and technical indicator values. The list of tickets includes both open positions and pending orders.
Property | Meaning |
currency | The deposit currency of the account |
balance | Account balance |
equity | Account equity |
pl | Floating profit/loss |
usedmargin | Margin in use |
freemargin | Free margin |
tickets | Number of "tickets": open positions and pending orders |
If the symbol name you are interested in is EURUSD, then the property name for its ask price is
=RTD("FXBlueLabs.ExcelRTD", , "156734", "askEURUSD")
Property | Meaning |
bidSymbol | Bid price of symbol |
askSymbol | Ask price of symbol |
highSymbol | Daily high of the symbol. Not available on all platforms. The definition of the day's start (e.g. GMT, or some other time zone) depends on the broker/platform. |
lowSymbol | Daily low of the symbol. Not available on all platforms. The definition of the day's start (e.g. GMT, or some other time zone) depends on the broker/platform. |
The app also provides a count and a list of all available symbols. For example, the following formulas return the number of available symbols and the name of the 5th symbol on the list (which can be in any order):
=RTD("FXBlueLabs.ExcelRTD", , "156734", "symbols")
=RTD("FXBlueLabs.ExcelRTD", , "156734", "s5")
Property | Meaning |
symbols | Number of symbols |
sN | Name of the nth symbol, e.g. EURUSD. The N value is an index between 1 and the total number of symbols |
The app supplies the following information about each "ticket", i.e. each open position and pending order. The N value in each property name is an index between 1 and the total number of tickets (reported by the tickets property).
For example, you can get the symbol name and net profit of the 2nd ticket (if there is one) using the following formulas:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "t2s")
=RTD("FXBlueLabs.ExcelRTD", , "156734", "t2npl")
Property | Meaning |
tNt | Ticket number, i.e. the ID of the open position or pending order |
tNa | Action: BUY, SELL, BUYLIMIT, SELLLIMIT, BUYSTOP, SELLSTOP |
tNs | |
tNv | |
tNnpl | Net profit (gross profit + commission + swap). Not applicable on pending orders, and reported as zero. |
tNpl | Gross profit. Not applicable on pending orders, and reported as zero. |
tNswap | Swap. Not applicable on pending orders, and reported as zero. |
tNcomm | Commission. Not applicable on pending orders, and reported as zero. |
tNsl | Stop-loss price |
tNtp | Take-profit price |
tNop | Open/entry price |
tNcp | Current price of symbol |
tNcm | Order comment |
tNmg | Order magic number (MetaTrader 4 only) |
tNot | Open time (as number of seconds since 1/1/1970) |
You can use the Excel RTD app to request recent price history from the platform. All values are bid prices.
The property name for bar history is as follows:
=RTD("FXBlueLabs.ExcelRTD", ,"156734", "@bh,EURUSD,H1,high,0")
The bar timeframe can either be specified as a number of minutes - e.g. 60 for hourly bars - or you can use standard notations such as H1 or M3. The available timeframes are as follows:
Period | Timeframe value |
M1 | 1 |
M2 | 2 |
M3 | 3 |
M4 | 4 |
M5 | 5 |
M6 | 6 |
M10 | 10 |
M12 | 12 |
M15 | 15 |
M30 | 30 |
H1 | 60 |
H2 | 120 |
H3 | 180 |
H4 | 240 |
H6 | 360 |
H8 | 480 |
D1 | 1440 |
W1 | 7200 |
You can request the following information about each bar:
Data | Meaning |
time | Start time of the bar (in the format yyyy/mm/dd hh:mm:ss) |
open | Open price |
high | High price |
low | Low price |
close | Close price |
range | Range from high to low |
median | Average of high and low |
typical | "Typical" price: average of high, low, and close |
weighted | "Weighted" price: average of high, low, close, and close - i.e. double-weighting on the close value |
change | Change in bar: close minus open, therefore negative for down bars and positive for up bars. |
abschange | Absolute change value, i.e. change converted to a positive number if negative |
The final part of the price history formula is the bar "shift", i.e. which bar to get information about. Bars are numbered with the newest at zero, and increasing in order of age. In other words, bar 0 is the current in-progress bar; bar 1 is the last complete bar etc.
Therefore, the close price on bar 0 (for any timeframe) is the current bid price. In effect, the following two formulas are identical:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "bidGBPUSD")
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@bh,GBPUSD,60,close,0")
The amount of data available on each timeframe depends on the underlying platform, but will typically be around 250 bars.
The Excel RTD app has some built-in indicator calculations which you can request using formulas. For example, the following formula will show 14-bar Relative Strength Index for GBP/USD M5:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@rsi,GBPUSD,M5,14,0")
The property name for a technical indicator starts with an indicator name such as
The first two parameters for an indicator are always the symbol name and the timeframe, which can be specified either as H2 or as the equivalent number of minutes such as 120.
The last parameter is always the bar "shift". You will normally want to use a value of 0 for the shift, in order to get the current indicator value, but you can also use a shift of e.g. 1 to get the value of the indicator at the end of the previous bar. (The only exception are the swing-point indicators, which always return the latest swing point and do not use a shift parameter.)
Many indicators can be applied to different data values from each bar, e.g. the high price or even the bar range instead of the close price.
Please bear in mind that exponential moving averages and similar calculations are affected by the amount of available bars. For convenience, everyone always refers to the N value in such calculations as "N bars" (e.g. "21-bar EMA"), but this is not what it truly means. The N is a weighting factor, and a calculation such as an EMA always looks at the entire bar history which it has collected, but giving increased weight to the most recent N bars. Two calculations of an EMA can be different - though only usually by small amounts - if they are using different amounts of bar history.
You can calculate a simple moving average (i.e. arithmetic mean) using the @sma indicator. For example, the following formula does an average of the median prices for the last 10 bars on GBP/USD M5:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@sma,GBPUSD,M5,median,10,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar, e.g. close or high |
period | Number of bars to calculate the average over |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate an exponential moving average using the @ema indicator. For example, the following formula does an average of the ranges of the last 21 bars on GBP/USD D1:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@ema,GBPUSD,1440,range,21,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar, e.g. close or high |
period | Number of bars to calculate the average over |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate a smoothed moving average using the @smma indicator. (A smoothed average with period N is the same as an exponential moving average with period 2N-1).
For example, the following formula does an average of the close prices of the last 21 bars on GBP/USD H1:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@smma,GBPUSD,H1,close,21,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar, e.g. close or high |
period | Number of bars to calculate the average over |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate a linear-weighted moving average using the @lwma indicator. For example, the following formula does an average of the ranges of the last 21 bars on GBP/USD D1:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@lwma,GBPUSD,1440,range,21,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar, e.g. close or high |
period | Number of bars to calculate the average over |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate MACD (the difference between a "fast" EMA and a "slow" EMA) using the @macd indicator. You can also use @macdsig to get the smoothed "signal" value of the MACD indicator.
For example, the following formula calculates MACD for GBP/USD M30, using the standard 12-bar fast EMA and a 26-bar slow EMA, and applying the calculation to the high price of each bar:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@macd,GBPUSD,30,high,12,26,9,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar, e.g. close or high |
fast | Number of bars for the fast EMA |
slow | Number of bars for the slow EMA |
slowing | Smoothing period for the signal value |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate average true range using the @atr indicator. For example, the following formula calculates the average true range of the last 21 bars on GBP/USD D1:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@atr,GBPUSD,D1,21,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
period | Number of bars to calculate the average over |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate Relative Strength Index using the @rsi indicator. For example, the following formula calculates 14-bar RSI on USD/JPY M3:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@rsi,USDJPY, 14,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
period | Number of bars to calculate the indicator over |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate the stochastic oscillator using the @stoch indicator. You can also calculate the slowed "signal" value for the indicator using @stochslow.
For example, the following formula calculates the oscillator on GBP/USD H2 bars, using standard parameters of (5,3,3) - i.e. K period of 5, D period of 5, slowing value of 3.
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@stoch,GBPUSD,120,5,3,3,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
k | K period for the calculation |
d | D period for the calculation |
slowing | Slowing period (moving average of D values) |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate "Bollinger" bands - a simple moving average plus/minus a number of standard deviations - using the @bbupper and @bblower indicators.
For example, the following formula calculates the upper band on GBP/USD M10, using an average of the close prices on the last 30 bars, and 2 standard deviations:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@bbupper,GBPUSD,10,close,30,2,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar, e.g. close or high |
period | Number of bars to calculate the indicator over |
deviations | Number of standard deviations to calculate (e.g. 2) |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate volatility - i.e. 1 standard deviation - using the @vol indicator.
For example, the following formula calculates the volatility of the last 21 bar-ranges on GBP/USD M10:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@vol,GBPUSD,10,range,21,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar, e.g. close or high |
period | Number of bars to calculate the indicator over |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate the Commodity Channel Index using the @cci indicator.
For example, the following formula calculates CCI using the typical bar price for the last 14 bars on EUR/USD H1:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@cci,EURUSD,60,typical,14,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar. CCI is usually calculated on the "typical" bar price |
period | Number of bars to calculate the indicator over |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate the highest of a series of bar values using the @high indicator. For example, the following formula calculates the highest high during the last 20 GBP/USD D1 bars:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@high,GBPUSD,D1,high,20,0")
The indicator can be applied to any bar data. For example, you can find the highest low as well as the highest high. You can also use it to find the bar with the largest range or change.
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar, e.g. "close" or "high" |
period | Number of bars to calculate the indicator over |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate the lowest of a series of bar values using the @low indicator. The indicator can be applied to any bar data. For example, you can find the lowest high as well as the lowest low. You can also use it to find the bar with the smallest range or change.
The following formula calculates the smallest D1 bar range during the last 20 GBP/USD D1 bars:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@low,GBPUSD,D1,range,20,0")
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar, e.g. "close" or "high" |
period | Number of bars to calculate the indicator over |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
You can calculate the most recent swing points using the @swingh and @swingl indicators. A swing point is defined as a bar with lower highs either side of it (or higher lows, for @swingl). These swing points are similar to the MT4 "Fractals" indicator.
For example, the following formulas finds the most recent swing-high and swing-low prices on GBP/USD M5, using a 5-bar swing (2 bars either side of swing point) and not allowing an "unconfirmed" swing involving the current bar:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@swingh,GBPUSD,M5,high,2,0")
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@swingl,GBPUSD,M5,low,2,0")
The indicator's parameters are as follows. Please note that the @swingh and @swingl do not have a bar "shift" parameter; they only return the most recent swing price.
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar. You normally use "high" with @swingh, and "low" with @swingl. However, you can use any value; for example, you can use "high" with @swingl to find a bar which has a lower high than the bars around it. |
swingbars | Number of higher/lower bars required either side of the swing bar. The usual value is 2, for a five-bar swing consisting of two lower highs/higher lows either side of the swing bar, but you can use any value from 1 (i.e. three-bar swing) upwards. |
unconfirmed | Either 0 or 1. Zero ignores the current bar and only allows "confirmed" swings. 1 includes the current bar, and allows "unconfirmed" swings which can change depending on price movements during the current bar. |
You can calculate Keltner channels using the @kelternupper and @keltnerlower indicators. A Keltner channel is an exponential moving average plus/minus average true range.
For example, the following formula calculates the lower Keltner channel on GBP/USD H1, using a 20-bar EMA minus half of 10-bar ATR:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@keltlower,GBPUSD,60,close,20,10,0.5,0")
Because Keltner channels are simply a combination of an EMA and ATR, the formula above is equivalent to the following:
=RTD("FXBlueLabs.ExcelRTD", , "156734", "@ema,GBPUSD,60,close,20,0") - (RTD("FXBlueLabs.ExcelRTD", , "156734", "@atr,GBPUSD,60,10,0") * 0.5)
The indicator's parameters are as follows:
Parameter | Meaning |
symbol | Symbol name, e.g. GBPUSD |
timeframe | Bar timeframe, as a number of minutes or a notation such as H1 or M3 |
data | Data to use from each bar, e.g. close or high, for calculating the EMA |
emaPeriod | Number of bars to use for the EMA |
atrPeriod | Number of bars to use for the ATR |
atrMultiple | Multiples of ATR to add to/subtract from the EMA |
shift | Bar shift, e.g. zero in order to get the current value of the indicator |
Other miscellaneous data items provided by the Excel RTD app are as follows:
Property | Meaning |
LastUpdateTime | Time of the last update from the RTD app. Will report 1/1/2000 if the RTD app is not running for the account. |
You can request prices and other market data using either the ID of instruments in Figaro or their display names.
The RTD widget reports the volumes on tickets as the cash/unit volume, not as a lot size. For example, a size of 0.20 lots will be reported as a volume of 20000.
The Excel RTD widget can be used to send simple trading commands from VBA code in Excel. You can also programmatically read the same data which is available via the RTD() function.
The following features can in fact be used from any programming language which supports COM, not just from VBA in Excel.
Note: VBA code can also use the HTTP interface described below, as well as the
You can read data programmatically using the
Set reader = CreateObject("FXBlueLabs.ExcelReader")
reader.Connect("156734")
MsgBox reader.Read("balance")
In other words: you create an instance of the
The property names for the
You can successfully create the
In order to check whether data is actually available you can use
If you are querying multiple pieces of data, particularly multiple pieces of ticket data, then you need to be careful about updates and data consistency. For example, consider the following code which loops through the ticket list:
For i = 1 To reader.Read("tickets")
strSymbol = reader.Read("t" & i & "s")
vVolume = reader.Read("t" & i & "v")
Next
It is possible for the following to happen:
To ensure consistency while reading multiple pieces of data, use
Reader.ReaderLock()
For i = 1 To reader.Read("tickets")
strSymbol = reader.Read("t" & i & "s")
vVolume = reader.Read("t" & i & "v")
Next
Reader.ReaderUnlock()
Don't forget to call
As a security measure, commands are turned off by default. You must turn on the "Accept commands" setting in the RTD widget in order to send commands successfully. If this option is turned off then all commands will return "ERR:Commands not allowed".
You can send simple commands from Excel using the
Set cmd = CreateObject("FXBlueLabs.ExcelCommand")
strResult = cmd.SendCommand("156734", "BUY", "s=EURUSD|v=10000", 5)
The
The return value from
There are some minor differences in the trading features which are supported by different broker trading platforms. For example, "magic numbers" are only valid for MT4 and MT5, and these parameters will be ignored on other platforms. Order comments are only available on some platforms.
The parameters for a command are sent as a pipe-delimited string, consisting of a number of settings in the format name=value. The parameters can be listed in any order, and some parameters are optional.
cmd.SendCommand("156734", "BUY", "s=EURUSD|v=10000", 5)
Trading volumes are always specified as cash amounts, not as lot sizes.
Simply returns the text
Submits buy or sell market orders. If successful, it returns the ID of the new ticket in the form
Parameter | Optional? | Meaning |
s | Compulsory | Symbol name for the buy order |
v | Compulsory | Trading volume |
sl | Optional | Stop-loss price for the new position |
tp | Optional | Take-profit price for the new position |
comment | Optional | Comment for the new position |
magic | Optional | Magic number for the new position |
Submits a new pending order. If successful, it returns the ID of the new ticket in the form
Parameter | Optional? | Meaning |
s | Compulsory | Symbol name for the buy order |
v | Compulsory | Trading volume |
price | Compulsory | Entry price for the pending stop/limit order |
sl | Optional | Stop-loss price for the new position |
tp | Optional | Take-profit price for the new position |
comment | Optional | Comment for the new position |
magic | Optional | Magic number for the new position |
Closes an open position or deletes a pending order. Returns
Parameter | Optional? | Meaning |
t | Compulsory | ID of the position to be closed, or the pending order to be deleted. |
Does a partial-close of an open position. Returns
Parameter | Optional? | Meaning |
t | Compulsory | ID of the position to be partially closed. |
v | Compulsory | Volume to be closed, e.g. 20000 |
Reverses an open position, e.g. closing an open sell and replacing it with a buy. Returns
Parameter | Optional? | Meaning |
t | Compulsory | ID of the position to be reversed |
v | Optional | Volume for the new reversed position. If omitted, the volume of the existing position is used (i.e. symmetrical reverse) |
sl | Optional | Stop-loss price for the new position |
tp | Optional | Take-profit price for the new position |
comment | Optional | Comment for the new position |
magic | Optional | Magic number for the new position |
Closes all open positions and pending orders for a specific symbol. Returns
Parameter | Optional? | Meaning |
s | Compulsory | Symbol name to close |
Closes all open positions and pending orders for all symbols. Returns
Parameter | Optional? | Meaning |
(none) |
For example:
cmd.SendCommand("156734", "CLOSEALL", "", 20) ' 20-second timeout
Changes the stop-loss on an open trade or pending order. Returns
Parameter | Optional? | Meaning |
t | Compulsory | ID of the trade or pending order to be modified |
sl | Compulsory | New stop-loss price, or 0 to remove any existing stop-loss |
Changes the take-profit on an open trade or pending order. Returns
Parameter | Optional? | Meaning |
t | Compulsory | ID of the trade or pending order to be modified |
tp | Compulsory | New take-profit price, or 0 to remove any existing take-profit |
Changes both the stop-loss and take-profit on an open trade or pending order. For pending orders, you can also alter the entry price.
Parameter | Optional? | Meaning |
t | Compulsory | ID of the trade or pending order to be modified |
p | Compulsory for pending orders | For pending orders, the new entry price for the order. Ignored and not required on open trades. |
sl | Compulsory | New stop-loss price, or 0 to remove any existing stop-loss |
tp | Compulsory | New take-profit price, or 0 to remove any existing take-profit |
Meaning | |
ERR:Need account | Channel for SendCommand() is blank |
ERR:Need command | Command value for SendCommand() is blank |
ERR:No listening app | Cannot find an running instance of the RTD widget for the specified widget |
ERR:No response within timeout | No response from the broker/platform within the specified number of seconds |
ERR:Commands not allowed | The "Allow commands" option is not turned on in the RTD widget |
ERR:Unrecognised command | The command value for SendCommand() is not understood by the RTD app |
ERR:Missing parameters | The command was missing one or more compulsory parameters |
It is also possible to send commands asynchronously rather than blocking execution of the VBA code until the command completes or times out. This works as follows:
For example:
Set cmd = CreateObject("FXBlueLabs.ExcelCommand")
lCommandId = cmd.SendCommandAsync("10915", "BUY", "s=EURUSD|v=10000", 60)
strResult = ""
While strResult = ""
strResult = cmd.CheckAsyncResult(lCommandId)
If strResult = "" Then MsgBox "Still waiting..."
Wend
cmd.FreeAsyncCommand (lCommandId)
You must eventually call
The Excel RTD widget lets you make http and websocket connections into Figaro (from apps on the local computer only, for security reasons). This gives you limited access to the Figaro scripting framework from outside the platform. You can read Figaro data and place trading requests from the language/environment of your choice, such as Python or .NET or an EA in MT4/5, without needing to (re-)write your code inside Figaro as a Javascript widget or script.
The communication is based on JSON: you send a block of JSON, in a websocket message or as the body of an http POST, and Figaro responds with JSON.
However, on http connections, there are also options for making a request as a GET rather than a POST, and for receiving output as XML rather than JSON. This allows data from Figaro to be imported into software such as Excel using its Data > From Web features.
You need to read this section of the guide in combination with the Figaro scripting reference:
https://www.fxblue.com/figaro/scripting/help
The scripting reference describes things such as the information available about an order or a market, and the format for data such as trading requests and candle requests.
This guide uses the general-purpose command-line tool
Similarly, this guide uses Javascript examples of websockets. Again, the interface is completely language-neutral, and can be used from any environment which can make websocket connections.
There are Node.js, C#, and Python examples of a websocket connection available from the following address. Even if you don't plan to use any of these languages, you may find these useful as further documentation of how to handle websocket connections and streaming updates of the account information:
Node.js: https://www.fxblue.com/figaro/excel-rtd/excel-rtd-node-js.zip
C#: https://www.fxblue.com/figaro/excel-rtd/excel-rtd-csharp.zip
Python: https://www.fxblue.com/figaro/excel-rtd/excel-rtd-python.zip
Websocket connections are available on port 31315. You connect to
The websocket connection sequence and lifecycle is as follows:
You connect to the Excel RTD widget (at
You wait for the initial message from the widget (which, uniquely, will not be JSON)
You send a connection message, stating the channel you want to talk to. This must match the channel setting in the Excel RTD widget.
The widget confirms or rejects your connection request
Once connected:
If you asked for streaming data in your connection request, the widget starts sending you streaming price and order data
The widget sends you "heartbeat" messages, at least every 60 seconds
You must send "heartbeat" messages to the widget, at least every 60 seconds
You can issue the commands described below
You need to wait for the initial message from the widget before sending a connection request. However, you don't need to inspect the contents of the initial message in any way.
Your connection request is simply a block of JSON with a
socket.send(JSON.stringify({
"channel": "156734",
"wantStreaming": true // Optional; defaults to false
}));
If your connection request is accepted, the widget will send you JSON containing
You and the widget need to exchange heartbeat messages at least every 60 seconds, or else the connection will be dropped. The message which you need to send, and which the widget similarly sends to you, is simply
After connection the widget can send you three types of message:
Heartbeat messages, at least every 60 seconds. These are simply
Streaming updates to prices, the order list etc. These contain
Responses to commands. These contain
Streaming-update messages - if requested with
Property | Meaning |
accountMetrics | Change to account metric such as equity or margin usage. Same as an account metrics message in the scripting framework: only contains the metrics which are changing. |
quotes[] | Array of prices which have changed. Same as a price message in the scripting framework. Notes: prices are only guaranteed to update and stream for markets where you have subscribed for prices. |
ordersOpened[] | Array of new orders or trades which have been opened. Same as an order message in the scripting framework. |
ordersClosed[] | Array of pending orders which have been deleted or of trades which have been closed. Same as an order message in the scripting framework. |
ordersChanged[] | Array of pending orders or trades which have changed (including a change in floating profit on open trades). Same as an order message in the scripting framework. |
positionsChanged[] | Changes to net positions. Same as a position message in the scripting framework: not issued on changes in profit. Only issued on new or closed orders which change the position size. |
candleChange | Change in the current candle within a candle store |
newCandle | Addition of a new candle to a candle store |
For example, a streaming-update message from the widget may look like the following:
{
"streaming": true,
"quotes": [
{"instrumentId": "EUR/USD", "b": 1.2345, "a": 1.2346},
{"instrumentId": "GBP/USD", "b": 1.2345, "a": 1.2346}
],
"ordersChanged": [
{"orderId": "T9765", "profit": 43.25, …}
],
"accountMetrics": {"floatingPL": 43.25, "equity": 10573.62}
}
It is common for a websocket connection to start by getting a complete snapshot of the account, and then to update that snapshot from streaming messages rather than repeatedly sending requests for the entire order list etc.
HTTP connections are available on port 31316. The URL which you connect to contains the channel name which you set in the Excel RTD widget. For example:
http://localhost:31316/channel/command
e.g. http://localhost:31316/156734/command
You communicate with the widget by POSTing a block of JSON as the body of your http request. For example, using
curl http://localhost:31316/156734/command --request POST --data-raw "{\"commandType\": \"SendOrder\", \"orderRequest\": {\"instrumentId\": \"EUR/USD\", \"tradingAction\": \"BUY\", \"volume\": {\"lots\": 0.01}}}"
This is simply POSTing the following JSON as the request body (with quote characters encoded as
{
"commandType": "SendOrder",
"orderRequest": {
"instrumentId": "EUR/USD",
"tradingAction": "BUY",
"volume": {"lots": 0.01}
}
}
If your command is accepted by the widget, then the response will be a block of JSON. If there is a problem with the format of your command, then the widget will set the HTTP status code to 400, and return a description of the problem.
HTTP connections can ask for XML output instead of JSON. You can do this by adding
http://localhost:31316/channel/command/xml
e.g. http://localhost:31316/156734/command/xml
There are two material changes in XML output compared to JSON:
Times are changed from their standard representation (a number of milliseconds since 1/1/1970) to a textual date representation in the form
Arrays are flattened into multiple nodes of the same type. For example, an
HTTP connections can also make GET requests instead of POST requests, putting the details of their command into the request querystring,. A value in the JSON such as
?commandType=SendOrder&orderRequest-instrumentID=EUR/USD&orderRequest-tradingAction=BUY&orderRequest-volume-lots=0.01
This combination of GET requests and XML output is mainly designed to allow the http interface to be used to import data into software such as Microsoft Excel. For example, the following URL lists the account history, with XML output:
http://localhost:31316/channel/command/xml?commandType=ListAccountHistory
You can then load this into Excel using its Data > From Web, giving you an import into Excel of the account history without any programming - and an import which you can update to current at any time using Data > Refresh All.
A command from you to the widget is simply a block of JSON which contains a
// Get size of current EUR/USD position
socket.send(JSON.stringify({
"commandType": "GetPosition",
"instrumentId": "EUR/USD"
}));
The widget's response will contain a
{
"responseToCommandType": "GetPosition",
"Position": { … }
}
On websocket connections, multiple commands may not be answered in the same order which you submit them. To link responses to requests, you can add a
// Get size of current EUR/USD position
socket.send(JSON.stringify({
"commandId": "myid1",
"commandType": "GetPosition",
"instrumentId": "EUR/USD"
}));
The widget's response will then look like this:
{
"responseToCommandType": "GetPosition",
"commandId": "myid1",
"Position": { … }
}
The scripting framework uses various enumerations, such as
In its responses to commands, the Excel RTD widget changes the numeric value to the corresponding member of the enumeration. For example, the description of an order will have a value such as "
The same is true in reverse when you send a trading command. The
The
Information about the account such as its deposit currency, and metrics such as equity and margin usage
A list of all available markets and latest-known prices
All pending orders and open trades
A list of positions: orders and trades aggregated into a single net figure for each market
It simply combines separate commands for GetAccount, ListInstruments, ListOrders, and ListPositions. The response will be in the following form. See below for more information.
{
"responseToCommandType": "Snapshot",
"Account": { … },
"Instruments": [ … ],
"Orders": [ … ],
"Positions": [ … ]
}
A snapshot is typically used by a websocket connection to get a complete initial picture of the trading account which the websocket connection then updates with streaming messages.
The
{
"responseToCommandType": "GetAccount",
"Account": {
"accountId": "12345678",
"balance": 9997.60,
"equity": 10021.30,
…
"features": {
"hedging": true,
…
}
}
}
There is also a
{
"responseToCommandType": "GetAccountMetrics",
"AccountMetrics": {
"balance": 9997.60,
"equity": 10021.30,
…
}
}
The
"responseToCommandType": "ListInstruments",
"Instruments": [
{"instrumentId": "EUR/USD", "bid": 1.2345, "ask": 1.2346, … },
{"instrumentId": "GBP/USD", "bid": 1.2345, "ask": 1.2346, … },
…
]
}
You can also request a single specific market using the
{
"commandType": "GetInstrument",
"instrumentId": "EUR/USD"
}
The
{
"responseToCommandType": "GetInstrument",
"Instrument": {
"instrumentId": "EUR/USD",
"bid": 1.2345,
…
}
}
Prices in an
Like in the scripting framework, the prices on a market are not guaranteed to be current or to update until/unless you subscribe for prices on that market.
There are two ways of subscribing for prices. The first is the
{
"commandType": "Subscribe",
"instrumentId": ["EUR/USD", "GBP/USD"]
}
The
You can get the latest price, for a single market, using the command
{
"commandType": "GetLatestPrice",
"instrumentId": "EUR/USD"
}
The response will contain a
{
"responseToCommandType": "GetLatestPrice",
"Quote": {
"instrumentId": "EUR/USD",
"bid": 1.2345,
"ask": 1.2346,
…
}
}
The scripting framework uses a single collection and a single object to represent both pending orders and open trades. As a result, the
{
"responseToCommandType": "ListOrders",
"Orders": [
{"orderId": "O12345", "orderType": "BUY_LIMIT", …},
{"orderId": "T12345", "orderType": "SELL", …}
}
}
Each item in the
You can request the current status of an individual pending order or open trade using the
{
"commandType": "GetOrder",
"orderId": "O12345"
}
You can also request positions (FXB.Position objects) from the framework - all the trades on a market aggregated into a single net-long or net-short figure. The
{
"responseToCommandType": "GetPositions",
"Positions": [
{"instrumentId": "EUR/USD", "longVolume": 0, "shortVolume": 10000 …},
{"instrumentId": "GBP/USD", "longVolume": 5000, "shortVolume": 2000 …},
…
}
}
The
{
"commandType": "GetPosition",
"instrumentId": "EUR/USD"
}
If there is no position in the market then this will return a
You can get the history on an account - all the historic credit movements as well as closed trades - using the
{
responseToCommandType: "ListAccountHistory",
TradeHistory: [
{"orderId": "D2387", "orderType": "DEPOSIT", "profit": 10000, …}
{"orderId": "T12345", "orderType": "BUY", …}
…
]
}
Note: there can be a substantial delay in retrieving the history.
You can make trading requests using the
The
{
"commandType": "SendOrder",
"orderRequest": {
"tradingAction": "CLOSEPOSITION",
"instrumentId": "EUR/USD"
}
}
You can also use all the options and variables which are permitted inside the scripting framework, such as risk-based volumes or candle-based prices. For example:
{
"commandType": "SendOrder",
"orderRequest": {
"tradingAction": "CHANGE",
"orderId": "T12345",
"timeframe": 3600, // Timeframe for candle-based stop-loss
"sl": {"bar": {"index": 1, "price": "l"}}, // Set s/l to the low of the previous H1 bar
"tp": {"pips": 30} // Set t/p to 30 pips from the current market price
}
}
The
The response from the framework will have a
{
"responseToCommandType": "SendOrder",
"result": {
"isOkay": false,
"isError": true,
"code": "TR_MARKETCLOSED"
}
}
There are two ways of getting candle data: the candle requests described here, and candle stores described below.
Candle requests to the Excel RTD widget are always non-streaming (they set
You request candle data using the
{
"commandType": "ListCandles",
"candleRequest": {
"instrumentId": "EUR/USD",
"timeframe": 3600
}
}
The
The response will include a
{
"responseToCommandType": "ListCandles",
"Candles": [
{"ts": 1609236000000, "o": 1.2345, …. },
{"ts": 1609228800000, "o": 1.2345, …},
…
]
}
Candle stores have two uses compared to the candle requests described above:
Candle stores can update with modified and new candles, generating streaming messages over websocket connections
Candle stores can include technical analysis calculations, such as moving averages or ATR
This gives you remote access to an FXB.CandleStore object in the scripting framework.
You create a candle store using the
{
"commandType": "CandleStore.Create",
"candleStore": {
"candleRequest": {
"instrumentId": "EUR/USD",
"timeframe": 3600
},
"ta": [
{"indicatorType": "EMA", "member": "c", "period": 20},
{"indicatorType": "ATR", "period": 14}
]
}
}
The
The
The
Candles stores can be either temporary or persistent. If the
If the
The response to
{
"responseToCommandType": "CandleStore.Create",
"candleStore": {
"persistent": true,
"candleStoreId": "123123123123123",
"candles": [
{"ts": 12346000, "o": 1.2345, "h": 12345, … },
…
],
"ta": [
{"indicatorType": "EMA", "values": [ 1.324234, 1.234234 … ]},
{"indicatorType": "ATR", "values": [ 1.324234, 1.234234 … ]},
]
}
}
If the store is persistent then the
The
If you provided a list of technical analysis calculations then the
Candle stores generate streaming messages over websocket connections provided that wantStreaming:true has been set for the websocket connection and that the candle store is persistent.
When the current candle changes, the streaming message looks like this:
{
"streaming": true,
"candleChange": {
"candleStoreId": "123123123123123",
"candle": {"ts": 12346000, "o": 1.2345, "h": 12345, … },
"ta": [
{"indicatorType": "EMA", "currentValue": 1.324234},
{"indicatorType": "ATR", "currentValue": 1.324234}
]
}
}
When a new candle starts, the format of the streaming message is the same except that it contains a
The contents of the
You should always eventually remove persistent candle stores, to free resources. You do this using the
{
"commandType": "CandleStore.Remove",
"candleStoreId": "123123123123123"
}
If a candle store is persistent then you can re-query its contents using the commands
{
"commandType": "CandleStore.GetAll",
"candleStoreId": "123123123123123"
}
The response is the complete data for the store, in the same format used when responding to creation of a store.
{
"commandType": "CandleStore.GetCandle",
"candleStoreId": "123123123123123",
"candleIndex": 0
}
The response to
{
"responseToCommandType": "CandleStore.GetCandle".
"candleStore": {
"candleStoreId": "123123123123123",
"candle": {"ts": 12346000, "o": 1.2345, "h": 12345, … },
"ta": [
{"indicatorType": "EMA", "value": 1.324234},
{"indicatorType": "ATR", "value": 1.324234}
]
}
}
Note: it is very inefficient to make frequent repeated use of
Use
Watch for the
On the start of a new candle, you may want to use