Intro
Continuing on from our previous post on How To Build An Automated Trading Bot in TradingView, where we created a trading system using moving average crossovers to enter and exit trades. Having completed the logic and automation algorithms for that system, we backtested it and are now ready to move on to implementing it in a live context. To do so we will use alerts to send trade data to MT4 from TradingView using Control Tower as the bridge.
If you haven’t read the previous article in this series, then I suggest you do and come back with the full code in your editor.
Sending Alerts to MT4 from TradingView
To convert our strategy to an automated bot which will communicate with MT4, we need to add alerts with the proper syntax to send the trade data to MT4 (and our broker).
ControlTower has a handy library which makes the process of encoding the trade data into MT4 format quick and easy.
First we will need to import the library. To do so we will add a single line of code to the top of our script on the below the the strategy declaration:
strategy('EMA Crossover Strategy', overlay=true)
import ParametricTrading/JSONFormatter4ControlTower/4 as JSON
Next we will add the call to the formatting function within an alert() along with the necessary variables. We will be replacing our strategy.entry() and strategy.close() calls from above with alerts that send trade orders to MT4. All together that block of code will be:
//ALERT CALLS WHICH SEND TRADE ORDER DATA TO MT4 VIA CONTROL TOWER
if time_cond //test if current candle is within the time parameters
if action == "LongEntry" or action == "ShortEntry"
alert(JSON.formatMarket(productID,symbol,action,risk,lots,0,0,takeProfit),alert.freq_once_per_bar_close)
if exitString == "LongExit" or exitString == "ShortExit"
alert(JSON.formatPartial(productID,symbol,exitString,closePercentage),alert.freq_once_per_bar_close)
All that’s left is to define the variables and insert them in the script before the alerts are called.
Defining Variables
Adding the variables can be as easy as this:
var productID = "f1"
var symbol = "EURUSD"
var action = "LongEntry"
var risk = 0
var lots = 1.0
var takeProfit = 1.20
var closePercentage = 100
While this is functional it is extremely limited. Instead of hardcoding the values let’s add a few of them to the user adjustable section above:
//TRADE PARAMETERStakeProfit = input.price(defval=0,title='Take Profit Price', group="Trade Parameters")lots = input.float(defval=0.5, title='Lot Size', step=.1, group="Trade Parameters")closePercentage = input.int(defval=100,title="Take Profit Percent", group="Trade Parameters")var symbol = syminfo.tickervar productID = "f1"risk = 0
To make things a bit sexier, let’s add the ability to plot the Take Profit price. Remember that we still have the time range parameters in effect which means that a trade won’t execute unless within the user assigned time range, so let’s add a little test of the time condition again and only assign a color value to a variable if the time_cond is true.
plotTakeProfitColor = time_cond ? color.green : na //only assign a color if within time parameters
And then when we plot the value of takeProfit we will use the variable plotTakeProfitColor as the value for the color argument of the plot. Like this:
plot(takeProfit,linewidth=4,color=plotTakeProfitColor,title="Take Profit Price", style=plot.style_line) //note this will only plot with a color if within the time range
Now we’ll only see the take profit price line within the time constraints defined in the user input section. Neat!
TradingView Webhook
Make sure you have the alert set up within TradingView to use a Webhook URL and that your custom webhook from ControlTower is inputted into the dialog box.
Going Live
Before we can use this strategy live we have to convert it from a strategy to an indicator. Strategies in TradingView are used for backtesting. Indicators work on live data and do not include backtesting functionality. In order to trigger real time alerts (and thus send our trade signals to our broker) we need to be using an indicator. The change is extremely simple:
We will change the opening line of the script to
indicator(‘EMA Crossover Strategy’, overlay=true)
And that’s it! We have now created an automated trading system in TradingView which connects to MT4. Our system is based on trading trends by following user-adjustable moving averages crosses.
Our final script is below:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
//@version=5
indicator('EMA Crossover Strategy', overlay=true)
import ParametricTrading/JSONFormatter4ControlTower/4 as JSON
////////////////////
// USER INPUT SECTION
//
// BACKTESTING RANGE
startDate = input.time (timestamp("01 Jan 2024"), '', group='Backtesting Date Range', inline='Start Period', tooltip="Select the start and end dates and times for the testing range. The strategy will only be tested within these dates.")
finishDate = input.time (timestamp("01 Jan 2025"), '', group='Backtesting Date Range', inline='Start Period')
time_cond = time >= startDate and time <= finishDate //we will use time_cond later to test if the current candle is within the selected dates by seeing if time_cond is TRUE
//CREATE USER-INPUT VARIABLES
periodShort = input.int(8, minval=1, title='Short Moving Average Length', group="Short Moving Average Selection",inline="shortMA", tooltip="Select the length and the type of moving average to use for the Short moving average.")
smoothingShort = input.string(title='Type', defval='EMA', options=['RMA', 'SMA', 'EMA', 'WMA', 'VWMA', 'SMMA', 'DEMA', 'TEMA', 'HullMA', 'LSMA'],inline="shortMA", group="Short Moving Average Selection")
periodLong = input.int(21, minval=1, title='Long Moving Average Length', group="Long Moving Average Selection",inline="longMA", tooltip="Select the length and the type of moving average to use for the Long moving average.")
smoothingLong = input.string(title='Type', defval='EMA', options=['RMA', 'SMA', 'EMA', 'WMA', 'VWMA', 'SMMA', 'DEMA', 'TEMA', 'HullMA', 'LSMA'], group="Long Moving Average Selection",inline="longMA")
periodExit = input.int(200, minval=1, title='Exit Moving Average Length', group="Exit Moving Average Selection",inline="exitMA", tooltip="Select the length and the type of moving average to use for the Exit moving average.")
smoothingExit = input.string(title='Type', defval='EMA', options=['RMA', 'SMA', 'EMA', 'WMA', 'VWMA', 'SMMA', 'DEMA', 'TEMA', 'HullMA', 'LSMA'], group="Exit Moving Average Selection",inline="exitMA")
//TRADE PARAMETERS
takeProfit = input.price(defval=0,title='Take Profit Price', group="Trade Parameters")
lots = input.float(defval=0.5, title='Lot Size', step=.1, group="Trade Parameters")
closePercentage = input.int(defval=100,title="Take Profit Percent", group="Trade Parameters")
var symbol = syminfo.ticker
var productID = "f1"
risk = 0
//////////////////////////////
//MOVING AVERAGE FUNCTION
//Moving Average Calculation for each type of moving average
ma(smoothing, period) =>
if smoothing == 'RMA'
ta.rma(close, period)
else
if smoothing == 'SMA'
ta.sma(close, period)
else
if smoothing == 'EMA'
ta.ema(close, period)
else
if smoothing == 'WMA'
ta.wma(close, period)
else
if smoothing == 'VWMA'
ta.vwma(close, period)
else
if smoothing == 'SMMA'
na(close[1]) ? ta.sma(close, period) : (close[1] * (period - 1) + close) / period
else
if smoothing == 'HullMA'
ta.wma(2 * ta.wma(close, period / 2) - ta.wma(close, period), math.round(math.sqrt(period)))
//ASSIGN A MOVING AVERAGE RESULT TO A VARIABLE
shortMA = ma(smoothingShort, periodShort)
longMA = ma(smoothingLong, periodLong)
exitMA = ma(smoothingExit, periodExit)
//PLOT THOSE VARIABLES
plotTakeProfitColor = time_cond ? color.green : na //only assign a color if within time parameters
plot(shortMA, linewidth=4, color=color.new(color.yellow, 0), title='The Short Moving Average')
plot(longMA, linewidth=4, color=color.new(color.blue, 0), title='The Long Moving Average')
plot(exitMA, linewidth=1, color=color.new(color.red, 0), title='The Exit Moving Average')
plot(takeProfit,linewidth=4,color=plotTakeProfitColor,title="Take Profit Price", style=plot.style_line) //note this will only plot with a color if within the time range
//ENTRY LOGIC
buy = ta.crossover(shortMA, longMA) ? true : na
sell = ta.crossunder(shortMA, longMA) ? true :na
action = buy ? "LongEntry" : sell ? "ShortEntry" : na //assign strings for use later with MT4 and Control Tower integration
//EXIT LOGIC
exitLong = ta.crossunder(close, exitMA) ? true : na
exitShort = ta.crossover(close, exitMA) ? true : na
exitString = exitLong ? "LongExit" : exitShort ? "ShortExit" : na //assign strings for use later with MT4 and Control Tower integration
//ALERT CALLS WHICH SEND TRADE ORDER DATA TO MT4 VIA CONTROL TOWER
if time_cond //test if current candle is within the time parameters
if action == "LongEntry" or action == "ShortEntry"
alert(JSON.formatMarket(productID,symbol,action,risk,lots,0,0,takeProfit),alert.freq_once_per_bar_close)
if exitString == "LongExit" or exitString == "ShortExit"
alert(JSON.formatPartial(productID,symbol,exitString,closePercentage),alert.freq_once_per_bar_close)
Save the indicator we’ve been working on as an indicator (using whatever name you would like) and then add it to your chart window.
Now we just need to send the alerts. Load a ticker or currency that you have backtested and feel confident will be profitable using our system, and click on the Alert icon.
Then from the pop up window, select the indicator name from the Condition menu and from the middle dropdown menu (which defaults to “Crossing”) select “Any alert() function call”.
Make sure you have Webhook URL enabled and have entered the correct URL from the Control Tower app.
Then click Create. Your alert will be listed in the alerts pane and will trigger when the crossover/crossunder conditions are met.
Make sure you have MT4 and Control Tower open. TradingView does not need to remain open.
When the short EMA crosses the long EMA, an alert will be sent to Control Tower which will immediately send it to MT4 for execution to your broker.
Congratulations! You have an automated bot trading system in TradingView executing orders to your broker of choice via MT4!