PineScript Syntax
After you have created your script and logic, you must create an Alert which contains the following parameters in JSON format (see examples for formatting method):
Syntax
alert("{ "productID":"f1", "symbol":"EURUSD", "action": "LongEntry", "openPrice":1.10, "risk" : 0, "lots": 1.0, "stopLoss": 0.99, "magicNumber": 0, "takeProfit": 1.20 }", alert.freq)
Arguments
productID: A string identifying the product registered with your license. You will have received this when you registered your license. Default is “f1”. Required.
symbol: A string containing the chart symbol you wish to trade. Required.
action: A string containing one of 9 options. Required. Possible values: LongEntry, ShortEntry, LongExit, ShortExit, buyLimit, sellLimit, buystop, sellStop, modifyOrder.
LongEntry: Used for placing opening market orders long. Used in an alert without an openPrice, this alert will open a long position at the current market price.
ShortEntry: Used for placing opening market orders short. Used in an alert without an openPrice, this alert will open a short position at the current market price.
LongExit: Used for placing closing market orders which are long. Used in an alert without an openPrice, this alert will close all long positions on the specified symbol at the current market price (unless a magicNumber other than 0 is specified).
ShortExit: Used for placing closing market orders which are short. Used in an alert without an openPrice, this alert will close all short positions on the specified symbol at the current market price (unless a magicNumber other than 0 is specified).
buyLimit: Used for setting Limit Orders in the long direction. Limit orders will be placed at the specified openPrice.
sellLimit: Used for setting Limit Orders in the short direction. Limit orders will be placed at the specified openPrice.
buyStop: Used for setting a long Stop-Limit order. Orders will be placed at the specified openPrice.
sellStop: Used for setting a short Stop-Limit order. Orders will be placed at the specified openPrice.
modifyOrder: Used for changing parameters of an open position, specifically stopLoss and takeProfit. magicNumber is required to identify the open position you wish to modify. Both stopLoss and takeProfit values must be included in the alert when using modifyOrder.
lots: An integer of the number of standard lots you wish to trade. Required. If you wish to use a percentage of your account equity, this must be set to 0 and use value in the risk parameter.
risk: An integer of the percentage of your account equity you wish to trade. Required. If you wish to use a lots size, this must be 0 and use the lots parameter.
stopLoss: An integer of the price where you want to place the stop loss.
takeProfit: An integer of the price where you want to place the take profit. Required.
magicNumber: An integer assigning a Magic Number to the order which is useful if multiple positions have been opened on the same symbol. Magic Numbers are numbers assigned to each trade order by MT4 to identify the specific open position. If not needed, the value must be 0 and MT4 will auto-assign its own magic number to the order. You can manually assign a Magic Number to a trade for your own identification purposes. This is useful when combined with exit orders to execute a partial close of a specific position if you have entered multiple positions on the same symbol. This allows you to run multiple strategies on the same symbol. Magic Numbers are also used to modify a specific order if there are multiple positions on a symbol.
openPrice: An integer of the price where you want the order to execute.
closePercentage: An integer used with LongExit or ShortExit. This is the percentage of your position you want to exit at the specified takeProfit price. If using lots instead of a percentage, the value of closePercentage must be 0.
Creating Alerts
In Pinescript you create a basic alert like this: alert(message string, frequency string)
. You can read about it here https://www.tradingview.com/pine-script-reference/v5/#fun_alert
You can also create an alert condition which you would use to manually setup the alert in the Create Alert dialog. You can read about it here: https://www.tradingview.com/pine-script-reference/v5/#fun_alertcondition
Either method requires the input of a message string in the body of the alert. For Control Tower to parse our alert message we must formulate the message string to include our commands in JSON format.
JSON requires line breaks between each argument to be on its own line. Within PineScript this requires adding a newline to each argument using the n
syntax. You will also need to escape the double quotes required by JSON around each Data Name/Value pair using . Note JSON requires a final newline after the last Data Pair.
Note there is a library which can be used to expedite the JSON formatting process. Please refer to the later section below in the documentation.
A full example
alert( + "{ \n + "productID + ": + "f1 + ", \n + "symbol + ": + "EURUSD + ", \n + "action + ": + "LongEntry + ", \n + "openPrice + ":1.10, \n + "risk + " : 0, \n + "lots + ": 1.0, \n + "stopLoss + ": 0.99, \n + "magicNumber + ": 0, \n + "takeProfit + ": 1.20 \n }", alert.freq_once_per_bar)
This will generate an alert message with the following output:
{
"symbol": "EURUSD",
"action": "LongEntry",
"openPrice":1.10,
"risk": 0,
"lots": 1.0,
"stopLoss": 0.99,
"magicNumber": 0,
"takeProfit": 1.20
}
Using Variables
Of course the above example uses hard coded values which isn’t particularly useful. To create more flexibility you would first define variables for each alert parameter and assigning them values based on the logic of your script. Note that each variable must be converted to a string within the message using the str.tostring(variable)
function. You would then integrate those variables into the alert message like this:
Continuing from our previous example, let’s create the following variables and assign them values:
symbol = syminfo.ticker
action = "LongEntry"
openPrice = 1.10
risk = 0
lots = 1.0
stopLoss = 0.99
magicNumber = 0
takeProfit = 1.20
alert("{\n "symbol":" " + str.tostring(symbol) + " ",\n "action":" " + str.tostring(action) + " ",\n "openPrice": " + str.tostring(openPrice) + ",\n "risk":" + str.tostring(risk) + ",\n "lots":" + str.tostring(lots) + ",\n "stopLoss":" + str.tostring(stopLoss) + ",\n "magicNumber":" + str.tostring(magicNum) + ",\n "takeProfit": " + str.tostring(takeProfit) + "\n}",alert.freq_once_per_bar)
Formatting JSON Using a Library
Manually formatting the alert strings into JSON is tedious, messy and prone to annoying errors. A much simpler way is to use the library we created just for this purpose! Libraries are pre-built functions which you can import into your script. I suggest you read about them here in the official documentation.
Importing the library
Using a library requires an import statement. The import statement for use with our JSON formatting function is:
import ParametricTrading/JSONFormatter4ControlTower/3 as JSONformatter
The Functions
There are 3 functions available in the library, one for each type of message you can send: Entry Orders, Modifying Orders and Partial Closes.
You can then call the formatting functions like this:
JSONformatter.formatEntry(productID,symbol,action,openPrice,risk,lots,stopLoss,magicNum,takeProfit)
JSONformatter.formatModify(productID,action,stopLoss,magicNum,takeProfit)
JSONformatter.formatPartial(productID,symbol,action,closePercentage)
symbol (string)
action (string)
openPrice (float)
risk (float)
lots (float)
stopLoss (float)
magicNum (int)
takeProfit (float)
Full Example
Putting it all together (not including the logic of your script), you would define your variables, create an alert condition and call the appropriate formatting function within the alert() call like this:
import ParametricTrading/JSONFormatter4ControlTower/3 as JSONformatter
var productID = "f1"
var symbol = "EURUSD"
var action = "LongEntry"
var openPrice = 1.10
var risk = 0
var lots = 1.0
var stopLoss = 0.99
var magicNum = 123456
var takeProfit = 1.20
var closePercentage = 33
if longEntry == True
alert(JSONformatter.formatEntry(productID,symbol,action,openPrice,risk,lots,stopLoss,magicNum,takeProfit),alert.freq_once_per_bar)
if firstTarget == True
alert(JSONformatter.formatPartial(productID,symbol,action,closePercentage), alert.freq_once_per_bar)
Modifying An Existing Order
It is possible to modify an existing order. To do so requires knowing the Magic Number of the existing order. (The Magic Number is an identification number of an order placed in MT4. If you set the Magic Number when you placed the trade, you would use the same number now. ) You can modify the stop loss or take profit price of the order.
The syntax to modify an order is as follows:
alert("{\n "action" : "modifyOrder", \n "magicNumber" : 1111, \n "stopLoss" : 1.11, \n "takeProfit" : 1.11 \n}", freq)
or using the library:
alert(JSONformatter.formatModify(productID,action,stopLoss,magicNum,takeProfit), alert.freq)
“action” : “modifyOrder”
“stopLoss”: Integer. Required. Thew new value of the stop loss for the position. If you do not wish to change the stop loss, you must provide the original value. This cannot be blank.
“magicNumber” : Integer. Required. This is the number of the existing order you wish to modify.
“takeProfit“: Integer. Optional. The new value of the take profit for the position.
Using Market Orders & closePercentage for Partial Take Profit
You can configure multiple alerts, each triggered by different logic sequences in your script. Thus in your script you could define a price where you would like to take partial profit. This value could either be assigned via an input or programmatically based on the complexity of your script. Either way, you would then trigger an alert that contained the following message string:
alert("{\n "symbol": " " + str.tostring(syminfo.ticker) + " ",\n "action" : " LongExit", \n "closePercentage" : 25 \n}", freq)
Or using the library:
alert(JSONformatter.formatPartial(productID,symbol,action,closePercentage), freq)
The above alert executes a Market Sell Order on the current symbol which sells 25% of the position. The remaining 75% of your position remains open and subject to the previous parameters you entered when you placed the trade. Likewise you could use “ShortExit” to execute a Market Buy Order if you had entered a short position.
Using Market Orders & closePercentage for an Automated Trailing Stop Loss
Using a closePercentage value of 100 and some logic which identifies pullbacks (such as ta.pivotlow) you could create an automated, price action-based trailing stop!
A code snippet to that effect could be:
import ParametricTrading/JSONFormatter4ControlTower/3 as JSONformatter
//SET UP A PIVOT HIGH AND PIVOT LOW ANALYSIS USING A USER-INPUTTED VALUE FOR i_trailLength WHICH ALLOWS THE USER TO FINE TUNE THE CALCULATION
o = open[i_trailLength], h = high[I_trailLength]
l = low[i_trailLength], c = close[I_trailLength]
ph = ta.pivothigh (close, i_trailLength, I_trailLength)
pl = ta.pivotlow (open, i_trailLength, I_trailLength)
valH = ta.valuewhen (ph, c, 0)
valL = ta.valuewhen (pl, c, 0)
valpH = ta.valuewhen (ph, c, 1)
valpL = ta.valuewhen (pl, c, 1)
n = bar_index
H = valH > valpH ? "HH" : valH < valpH ? "LH" : na
L = valL < valpL ? "LL" : valL > valpL ? "HL" : na
//TEST FOR IF IT IS PIVOT HIGH OR PIVOT LOW AND IF WITHIN THE TIME CONSTRAINTS (SETUP ELSEWHERE IN THE SCRIPT TO PREVENT ANALYZING THE ENTIRE CHART HISTORY)
if ph and direction == "SHORT" and time_cond
trailSL := math.max(h,l)
if pl and direction == "LONG" and time_cond
trailSL := math.min(h,l)
//CHECK IF PRICE CROSSES THE PIVOT HIGH OR LOW AND ASSIGN A VARIABLE TO TRUE
if ta.crossunder(close,trailSL) and direction == "LONG" and time_cond
longSL := true
if ta.crossover(close,trailSL) and direction == "SHORT" and time_cond
shortSL := true
//IF A CROSSOVER OF THE TRAILING SL (AKA PIVOT HIGH/LOW) HAS OCCURRED, THEN TRIGGER AN ALERT WHICH CLOSES 100% OF THE POSITION
if longSL or shortSL
slText = longSL ? "LongExit" : "ShortExit"
alert(JSONformatter.formatPartial("f1",syminfo.ticker,str.tostring(slText),100),alert.freq_once_per_bar_close)