Super 8 - 30M BTC.txt
Copy
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © AssassinsGrid
// 🚀 Welcome to the Ultimate Trading Script!
// 📈 Explore a new era of trading with this powerful and versatile Pine script. Whether you're a seasoned trader or just starting, this script is designed to elevate your trading game across various assets.
// ⚙️ Key Features:
//
// 📊 **EMA & ADX Customization**: Fine-tune your strategy with customizable lengths for Exponential Moving Averages (EMAs) and Average Directional Index (ADX). Gain precise trend insights.
//
// ⚡ **SAR Optimization**: Adjust parameters for the Parabolic SAR to enhance your trading results.
//
// 🤔 **Position Flexibility**: Choose your position wisely – Long, Short, or Both. It's all about your trading preference.
//
// 💹 **Take Profit & Stop Loss**: Define your profit targets and risk tolerance with various options like Normal, ATR, and more.
//
// 🔄 **Pyramiding Strategies**: Maximize your gains by controlling the number of trades within a position. Incremental or Normal – you decide!
//
// 🌐 **Backtest with Precision**: Set your backtesting period and witness how your strategy performs over time.
// ⚠️ **Note**: Every great strategy has its unique characteristics. Ensure to customize parameters according to your risk tolerance and market conditions.
// 💰 Happy Trading! 💰
//@version=5
// ———————————————————— Strategy Settings
strategy('Super 8 - 30m BTCUSDT.P', shorttitle = 'Super 8',
// The overlay parameter is set to true, which means that the strategy will be plotted on top of the price chart
overlay = true,
// The default_qty_value parameter is set to 0, meaning that the position size will be calculated based on the available capital
default_qty_value = 0,
// The initial_capital parameter is set to 10000, which is the starting capital for the strategy
initial_capital = 10000,
// The pyramiding parameter is set to 0, because it will be controlled by the script
pyramiding = 0,
// The commission_value parameter is set to 0.04, which represents a 0.04% commission for each trade
commission_value = 0.05,
// The commission_type parameter is set to strategy.commission.percent, which means that the commission is a percentage of the trade value
commission_type = strategy.commission.percent,
// The process_orders_on_close parameter is set to true, which means that orders will be executed at the close of the bar
process_orders_on_close = true,
// To open long positions with a maximum leverage of 100X, a margin requirement of 1.5% is needed.
margin_long = 1.5,
// To open short positions with a maximum leverage of 100X, a margin requirement of 1.5% is needed.
margin_short = 1.5,
// The use_bar_magnifier parameter is set to false, which means that the chart will not use a bar magnifier
use_bar_magnifier = false)
// ———————————————————— Inputs
// ————— Source input
// Define the position to take (long, short, or both)
Position = input.string('Both', 'Long / Short', options = ['Long', 'Short', 'Both'], tooltip = "Choose the position to take (long, short, or both)")
// ————— EMA inputs
// Define the slow and fast EMA lengths
sEma_Length = input.int(500, 'Slow EMA Length', minval = 0, step = 25, group = 'EXPONENTIAL MOVING AVERAGE', tooltip = "Set the length of the slow EMA")
fEma_Length = input.int(100, 'Fast EMA Length', minval = 0, step = 25, group = 'EXPONENTIAL MOVING AVERAGE', tooltip = "Set the length of the fast EMA")
// ————— ADX inputs
// Define the ADX parameters
ADX_len = input.int(28, 'ADX Length', minval = 1, group = 'AVERAGE DIRECTIONAL INDEX', tooltip = "Set the length of the ADX")
ADX_smo = input.int(9, 'ADX Smoothing', minval = 1, group = 'AVERAGE DIRECTIONAL INDEX', tooltip = "Set the smoothing of the ADX")
th = input.float(20.5, 'ADX Threshold', minval = 0, step = 0.5, group = 'AVERAGE DIRECTIONAL INDEX', tooltip = "Set the threshold for the ADX")
// ————— SAR inputs
// Define the SAR parameters
Sst = input.float(0.1, 'SAR star', minval = 0.01, step = 0.01, group = 'PARABOLIC SAR', tooltip = "Set the starting value for the SAR")
Sinc = input.float(0.04, 'SAR inc', minval = 0.01, step = 0.01, group = 'PARABOLIC SAR', tooltip = "Set the increment value for the SAR")
Smax = input.float(0.4, 'SAR max', minval = 0.01, step = 0.01, group = 'PARABOLIC SAR', tooltip = "Set the maximum value for the SAR")
// ————— MOVING AVERAGE CONVERGENCE DIVERGENCE
// Define the MACD and the MAC-Z parameters
MACD_options = input.string('MACD', 'MACD OPTION', options = ['MACD', 'MAC-Z'], group = 'MOVING AVERAGE CONVERGENCE DIVERGENCE', tooltip="Select the type of MACD to use. The MAC-Z is designed to reduce false signals compared to the standard MACD")
fastLength = input.int(24, 'MACD Fast MA Length', minval = 1, group = 'MOVING AVERAGE CONVERGENCE DIVERGENCE', tooltip = "Number of periods for the fast moving average.")
slowLength = input.int(52, 'MACD Slow MA Length', minval = 1, group = 'MOVING AVERAGE CONVERGENCE DIVERGENCE', tooltip = "Number of periods for the slow moving average.")
signalLength = input.int(11, 'MACD Signal Length', minval = 1, group = 'MOVING AVERAGE CONVERGENCE DIVERGENCE', tooltip = "Number of periods for the signal line.")
lengthz = input.int(14, 'Z-VWAP Length', minval = 1, group = 'MOVING AVERAGE CONVERGENCE DIVERGENCE', tooltip = "Number of periods for the Z-VWAP used in the MAC-Z calculation.")
lengthStdev = input.int(14, 'StDev Length', minval = 1, group = 'MOVING AVERAGE CONVERGENCE DIVERGENCE', tooltip = "Number of periods for the standard deviation used in the MAC-Z calculation.")
A = input.float(-0.2, "MAC-Z constant A", minval = -2.0, maxval = 2.0, step = 0.1, group = 'MOVING AVERAGE CONVERGENCE DIVERGENCE', tooltip = "Constant A used in the MAC-Z calculation.")
B = input.float(0.4, "MAC-Z constant B", minval = -2.0, maxval = 2.0, step = 0.1, group = 'MOVING AVERAGE CONVERGENCE DIVERGENCE', tooltip = "Constant B used in the MAC-Z calculation.")
// ————— Volume inputs for entries condition and for calculate quantities later
// Define volume factor and simple moving average length for volume condition
volume_f = input.float(0.4, 'Volume Factor', minval = 0, step = 0.1, group = 'VOLUME CONDITION', tooltip = "Factor used to determine the minimum required volume for an entry.")
sma_Length = input.int(55, 'SMA Volume Length', minval = 1, group = 'VOLUME CONDITION', tooltip = "Number of periods for the simple moving average used in the volume condition.")
// ————— Bollinger Bands inputs
// Define inputs for Bollinger Bands
BB_Length = input.int(40, 'BB Length', minval = 1, group = 'BOLLINGER BANDS', tooltip = "Length of the Bollinger Bands period")
BB_mult = input.float(2.2, 'BB Multiplier', minval = 0.1, step = 0.1, group = 'BOLLINGER BANDS', tooltip = "Multiplier for the Bollinger Bands width")
bbMinWidth01 = input.float(5.0, 'Min. BB Width % (New Position)', minval = 0, step = 0.5, group = 'BOLLINGER BANDS', tooltip = "Minimum width of the Bollinger Bands to enter a new position")
bbMinWidth02 = input.float(2.0, 'Min. BB Width % (Pyramiding)', minval = 0, step = 0.5, group = 'BOLLINGER BANDS', tooltip = "Minimum width of the Bollinger Bands to add to an existing position")
// ————— Take Profit / Trailing Stop input
// Define take profit/trailing stop options and parameters
TP_options = input.string('Both', 'Take Profit Option', options = ['Normal', 'Donchian', 'Both'], group = 'TAKE PROFIT / TRAILING STOP', tooltip = "Option for the take profit / trailing stop")
tp = input.float(1.8, 'Take Profit %', minval = 0, step = 0.1, group = 'TAKE PROFIT / TRAILING STOP', tooltip = "Percentage profit target")
trailOffset = input.float(0.3, 'Trail offset %', minval = 0, step = 0.1, group = 'TAKE PROFIT / TRAILING STOP', tooltip = "The offset percentage used for the trailing stop. If set to 0, only the Take Profit option will be used. If set to a value greater than 0, the Trailing Stop option will be used and the use_bar_magnifier parameter must also be set to true for more realistic results.")
// ————— TP Donchian Channel Input
// Define Donchian Channel period for take profit option
DClength = input.int(55, title='Donchian Channel Period', minval = 1, group='TAKE PROFIT / TRAILING STOP', tooltip = 'Defines the period of the Donchian Channel used for the take profit option.')
// ————— Stop Loss input
// Define stop loss options and parameters
SL_options = input.string('Both', 'Stop Loss Option', options = ['Normal', 'ATR', 'Both'], group = 'STOP LOSS', tooltip = 'Select the type of stop loss option you want to use.')
sl = input.float(8.0, 'Stop Loss %', minval = 0, step = 0.5, group = 'STOP LOSS', tooltip = 'Defines the percentage value of the stop loss.')
// ————— SL ATR Inputs
// Define ATR period and multiplier for ATR stop loss option
atrPeriodSl = input.int(14, title='ATR Period', minval = 0, group='STOP LOSS', tooltip = 'Defines the period of the Average True Range used in the ATR stop loss option.')
multiplierPeriodSl = input.float(15, 'ATR Multiplier', minval = 0, step = 0.5, group = 'STOP LOSS', tooltip = 'Defines the multiplier used in the ATR stop loss option.')
// ————— Risk input
// Define maximum risk percentage
Risk = input.float(5, 'Max. Risk %', tooltip = "Set the maximum percentage of account balance you're willing to risk per position", minval = 0, maxval = 100, group = 'RISK')
// ————— Pyramiding
// Define pyramiding options and parameters
Pyr = input.int(3, 'Max. Pyramiding', tooltip = "Set the maximum number of trades you are willing to open within a position", minval = 1, maxval = 10, group = 'PYRAMIDING')
StepEntry = input.string('Incremental', 'Step Entry Mode', tooltip = "Select the way you want to add new trades", options = ['Normal', 'Incremental'], group = 'PYRAMIDING')
bbBetterPrice = input.float(0.7, 'Min. Better Price %', tooltip = "Set the minimum better price percentage you want to get when adding new trades", minval = 0.1, step = 0.1, group = 'PYRAMIDING')
// ————— Backtest input
// Setting the start date for the backtesting period as January 1, 2000 at 1:00 UTC
StartDate = timestamp('01 Jan 2000 01:00 +000')
// Setting the start of the trading period for the backtest, using the start date above as the default value
testPeriodStart = input.time(StartDate, 'Start of Trading', tooltip = "Set the start date and time of the backtesting period", group = 'BACKTEST')
// ———————————————————— Average Price Variable
// Setting the average price variable to the close price of each candle, and using the strategy's average price if available
float AveragePrice = close
AveragePrice := nz(strategy.position_avg_price, close)
// ———————————————————— Exponential Moving Average
// Calculating the slow and fast Exponential Moving Averages (EMAs) using the close price
sEMA = ta.ema(close, sEma_Length)
fEMA = ta.ema(close, fEma_Length)
// Setting the conditions for a long or short signal based on the relationship between the fast and slow EMAs
bool EMA_longCond = na
bool EMA_shortCond = na
EMA_longCond := fEMA > sEMA and sEMA > sEMA[1]
EMA_shortCond := fEMA < sEMA and sEMA < sEMA[1]
// Plotting the EMAs on the chart and coloring them based on the long and short conditions
EMA_color = EMA_longCond ? color.new(color.green, 50) : EMA_shortCond ? color.new(color.red, 50) : color.new(color.orange, 50)
plot(sEMA, 'Slow EMA', EMA_color, 3)
plot(fEMA, 'Fast EMA', EMA_color, 2)
// ———————————————————— ADX
// Calculating the Directional Indicator Plus (+DI), Directional Indicator Minus (-DI), and Average Directional Movement Index (ADX)
[DIPlus, DIMinus, ADX] = ta.dmi(ADX_len, ADX_smo)
// Setting the conditions for a long or short signal based on the relationship between +DI and -DI and the ADX value
bool ADX_longCond = na
bool ADX_shortCond = na
ADX_longCond := DIPlus > DIMinus and ADX > th
ADX_shortCond := DIPlus < DIMinus and ADX > th
// Coloring the bars on the chart based on the long and short conditions
ADX_color = ADX_longCond ? color.new(color.green, 25) : ADX_shortCond ? color.new(color.red, 25) : color.new(color.orange, 25)
barcolor(color = ADX_color, title = 'ADX')
// ———————————————————— SAR
// Calculating the Parabolic SAR (SAR) based on the parameters set for step, max, and acceleration factor
SAR = ta.sar(Sst, Sinc, Smax)
// Setting the conditions for a long or short signal based on the relationship between the SAR value and the close price
bool SAR_longCond = na
bool SAR_shortCond = na
SAR_longCond := SAR < close
SAR_shortCond := SAR > close
// Plotting the SAR on the chart and coloring it based on the long and short conditions
plot(SAR, 'SAR', SAR_longCond ? color.new(color.green, 50) : color.new(color.red, 50), style = plot.style_circles)
// ———————————————————— MACD
// Calculating the Moving Average Convergence Divergence (MACD) and its signal line, as well as the MACD-Z value
// Define three variables lMACD, sMACD, and hist by calling the ta.macd() function using the 'close', 'fastLength', 'slowLength', and 'signalLength' as parameters
[lMACD, sMACD, hist] = ta.macd(close, fastLength, slowLength, signalLength)
// ————— MAC-Z calculation
// Define a function calc_zvwap(pds) that calculates the z-score of the volume-weighted average price (VWAP) of 'close' for a given period 'pds'
calc_zvwap(pds) =>
mean = math.sum(volume * close, pds) / math.sum(volume, pds)
vwapsd = math.sqrt(ta.sma(math.pow(close - mean, 2), pds))
(close - mean) / vwapsd
// Define float variables
float zscore = na
float fastMA = na
float slowMA = na
float macd = na
float macz = na
float signal = na
float histmacz = na
// Call the function calc_zvwap(lengthz) to calculate the z-score of the VWAP for a given period 'lengthz'
zscore := calc_zvwap(lengthz)
// Calculate the simple moving averages of the 'close' prices using 'fastLength' and 'slowLength' periods, and assign them to 'fastMA' and 'slowMA' respectively
fastMA := ta.sma(close, fastLength)
slowMA := ta.sma(close, slowLength)
// Assign the 'lMACD' variable to 'macd'
macd := lMACD
// Calculate 'macz' by multiplying the z-score by a constant 'A',
// adding the 'macd' value, and dividing by the product of the standard deviation of the 'close' prices over a period 'lengthStdev' and a constant 'B'
macz := (zscore * A) + (macd / (ta.stdev(close, lengthStdev) * B))
// Calculate the simple moving average of the 'macz' values over a period 'signalLength' and assign it to 'signal'
signal := ta.sma(macz, signalLength)
// Calculate the difference between 'macz' and 'signal' and assign it to 'histmacz'
histmacz := macz - signal
// ————— MACD conditions
// Define two boolean variables 'MACD_longCond' and 'MACD_shortCond'
bool MACD_longCond = na
bool MACD_shortCond = na
// If 'MACD_options' is equal to 'MACD', check if the 'hist' value is greater than 0 and assign the result to 'MACD_longCond';
// otherwise, check if 'histmacz' is greater than 0 and assign the result to 'MACD_longCond'
MACD_longCond := MACD_options == 'MACD' ? hist > 0 : histmacz > 0
// If 'MACD_options' is equal to 'MACD', check if the
MACD_shortCond := MACD_options == 'MACD' ? hist < 0 : histmacz < 0
// ———————————————————— Bollinger Bands
// ————— BB calculation
// Calculates the middle, upper and lower bands using the Bollinger Bands technical analysis indicator
[BB_middle, BB_upper, BB_lower] = ta.bb(close, BB_Length, BB_mult)
// ————— Bollinger Bands width
// Calculates the width of the Bollinger Bands
float BB_width = na
BB_width := (BB_upper - BB_lower) / BB_middle
// ————— Long Bollinger Bands conditions
// Defines the conditions for entering a long position using Bollinger Bands
// New Longs
bool BB_long01 = na
BB_long01 := Position != 'Short' and not ADX_shortCond and ta.crossunder(low, BB_lower) and EMA_longCond and BB_width > (bbMinWidth01 / 100)
// Pyramiding Longs
bool BB_long02 = na
BB_long02 := Position != 'Short' and not ADX_shortCond and ta.crossunder(low, BB_lower) and EMA_longCond and BB_width > (bbMinWidth02 / 100)
// ————— Short Bollinger Bands conditions
// Defines the conditions for entering a short position using Bollinger Bands
// New Shorts
bool BB_short01 = na
BB_short01 := Position != 'Long' and not ADX_longCond and ta.crossover(high, BB_upper) and EMA_shortCond and BB_width > (bbMinWidth01 / 100)
// Pyramiding Shorts
bool BB_short02 = na
BB_short02 := Position != 'Long' and not ADX_longCond and ta.crossover(high, BB_upper) and EMA_shortCond and BB_width > (bbMinWidth02 / 100)
// ————— Bollinger Bands plotting
// Plots the Bollinger Bands on the chart.
u_BB = plot(BB_upper, 'Upper Bollinger Band', EMA_color, 2)
l_BB = plot(BB_lower, 'Lower Bollinger Band', EMA_color, 2)
fill(u_BB, l_BB, title = 'Bollinger Band Background', color = fEMA > sEMA ? color.new(color.green, 95) : color.new(color.red, 95))
// ———————————————————— Volume
// Defines conditions for long and short positions based on volume
bool VOL_longCond = na
bool VOL_shortCond = na
VOL_longCond := volume > ta.sma(volume, sma_Length) * volume_f
VOL_shortCond := VOL_longCond
// ———————————————————— Strategy
// Defines the long and short conditions for entering a trade based on multiple indicators and volume
bool longCond = na
longCond := Position != 'Short' and EMA_longCond and ADX_longCond and SAR_longCond and MACD_longCond and VOL_longCond
bool shortCond = na
shortCond := Position != 'Long' and EMA_shortCond and ADX_shortCond and SAR_shortCond and MACD_shortCond and VOL_shortCond
// ———————————————————— Take Profit
// ————— Donchian Channels Calculation
// Calculates the Donchian Channels for determining take profit levels
float DClower = na
float DCupper = na
float DCbasis = na
DClower := ta.lowest(DClength)
DCupper := ta.highest(DClength)
DCbasis := math.avg(DCupper, DClower)
// ————— Take Profit Conditions
// Determines the take profit levels based on the selected options
float longPriceProfit = na
float shortPriceProfit = na
if TP_options == 'Both'
// Calculate the long and short take profit levels if both options are selected
longPriceProfit := math.max(DCupper, (1 + (tp / 100)) * AveragePrice)
shortPriceProfit := math.min(DClower, (1 - (tp / 100)) * AveragePrice)
else if TP_options == 'Normal'
// Calculate the normal take profit levels if that option is selected
longPriceProfit := (1 + (tp / 100)) * AveragePrice
shortPriceProfit := (1 - (tp / 100)) * AveragePrice
else if TP_options == 'Donchian'
// Calculate the Donchian take profit levels if that option is selected
longPriceProfit := math.max(DCupper, AveragePrice)
shortPriceProfit := math.min(DClower, AveragePrice)
// ————— Take Profit Plotting
// Plot the take profit levels on the chart
plot(strategy.position_size > 0 ? longPriceProfit : strategy.position_size < 0 ? shortPriceProfit : na,
'Take Profit', strategy.position_size > 0 ? color.new(color.blue, 30) : color.new(color.red, 30), 2, plot.style_circles)
// ———————————————————— ATR Stop Loss
// ————— ATR Calculation
// Calculate the ATR stop loss levels
float ATR_SL_Long = low - ta.atr(atrPeriodSl) * multiplierPeriodSl
float ATR_SL_Short = high + ta.atr(atrPeriodSl) * multiplierPeriodSl
float longStopPrev = nz(ATR_SL_Long[1], ATR_SL_Long)
float shortStopPrev = nz(ATR_SL_Short[1], ATR_SL_Short)
ATR_SL_Long := open > longStopPrev ? math.max(ATR_SL_Long, longStopPrev) : ATR_SL_Long
ATR_SL_Short := open < shortStopPrev ? math.min(ATR_SL_Short, shortStopPrev) : ATR_SL_Short
// ————— Price Stop
// Calculate the price stop levels
float longPriceStop = na
float shortPriceStop = na
if SL_options == 'Both'
// Calculate the long and short price stop levels if both options are selected
longPriceStop := math.max(ATR_SL_Long, (1 - (sl / 100)) * AveragePrice)
shortPriceStop := math.min(ATR_SL_Short, (1 + (sl / 100)) * AveragePrice)
else if SL_options == 'Normal'
// Calculate the normal price stop levels if that option is selected
longPriceStop := (1 - (sl / 100)) * AveragePrice
shortPriceStop := (1 + (sl / 100)) * AveragePrice
else if SL_options == 'ATR'
// Calculate the ATR price stop levels if that option is selected
longPriceStop := ATR_SL_Long
shortPriceStop := ATR_SL_Short
// ————— Variable Stop Loss %
// Calculate the variable stop loss percentage levels
float slPercentLong = na
slPercentLong := (math.max(0, (AveragePrice - longPriceStop)) / AveragePrice) * 100
float slPercentShort = na
slPercentShort := (math.max(0, (shortPriceStop - AveragePrice)) / AveragePrice) * 100
// ————— Stop Loss plotting
// Plots the stop loss level based on the current position size and whether it's a long or short position
// Uses circles to visualize the stop loss level
plot(strategy.position_size > 0 ? longPriceStop : strategy.position_size < 0 ? shortPriceStop : na,
'Stop Loss', strategy.position_size > 0 ? color.new(color.aqua, 80) : color.new(color.purple, 70), 2, plot.style_circles)
// ————— Average price plotting
// Plots the average price of the current position, using a cross to visualize the price level
// Uses different colors depending on whether it's a long or short position
plot(ta.change(strategy.position_avg_price) ? strategy.position_avg_price : na,
'Average price', strategy.position_size > 0 ? color.new(color.aqua, 20) : color.new(color.yellow, 20), 2, plot.style_cross)
// ———————————————————— Backtest
// Define the variable "Equity" and assign it the value of "strategy.equity"
float Equity = strategy.equity
// Define the variable "Balance" and assign it the sum of "strategy.initial_capital" and "strategy.netprofit"
float Balance = strategy.initial_capital + strategy.netprofit
// Define the variable "RealizedPnL" and assign it the value of "strategy.netprofit"
float RealizedPnL = strategy.netprofit
// Define the variable "Floating" and assign it the value of "strategy.openprofit"
float Floating = strategy.openprofit
// Calculate the percentage of "Floating" relative to "Balance" and assign it to "PFloating"
float PFloating = (Floating / Balance) * 100
// Calculate the percentage of "RealizedPnL" relative to "strategy.initial_capital" and assign it to "PRealizedPnL"
float PRealizedPnL = (RealizedPnL / strategy.initial_capital) * 100
// Calculate the sum of "Floating" and "RealizedPnL" and assign it to "URealizedPnL"
float URealizedPnL = Floating + RealizedPnL
// Calculate the percentage of "URealizedPnL" relative to "strategy.initial_capital" and assign it to "PURealizedPnL"
float PURealizedPnL = ((URealizedPnL) / strategy.initial_capital) * 100
// Calculate the profit factor by dividing "strategy.grossprofit" by "strategy.grossloss" and assign it to "ProfitFactor"
float ProfitFactor = strategy.grossprofit / strategy.grossloss
// Calculate the position size by multiplying "strategy.position_size" and "strategy.position_avg_price" and assign it to "PositionSize"
float PositionSize = strategy.position_size * strategy.position_avg_price
// Calculate the cash by subtracting the product of "nz(PositionSize)" and "marginRate" from "Balance" and assign it to "Cash"
float Cash = Balance - (nz(PositionSize) * 0.015)
// Calculate the profitability by dividing "strategy.wintrades" by the sum of "strategy.wintrades" and "strategy.losstrades", multiplying by 100, and assign it to "Profitability"
float Profitability = (strategy.wintrades / (strategy.wintrades + strategy.losstrades)) * 100
// Calculate the leverage parameter by dividing the absolute value of "PositionSize" by "Balance" and assign it to "LeverageParameter"
float LeverageParameter = math.abs(nz(PositionSize / Balance))
// Calculate the trading time by subtracting "strategy.closedtrades.entry_time(0)" from "time_close" and assign it to "TradingTime"
int TradingTime = time_close - strategy.closedtrades.entry_time(0)
// ————— Creating the Table
// Create a table with a specific format and assign it to a variable
var InfoPanel = table.new(position.middle_left, 2, 10, na, color.new(color.white, 80), 1, color.new(color.white, 80), 1)
// Define a function for the table formatting
ftable(_table_id, _column, _row, _text, _text_color) =>
table.cell(_table_id, _column, _row, _text, 0, 0, _text_color, text.align_left, text.align_center, size.tiny, na)
// Function to convert time in milliseconds to string format
tfString(int timeInMs) =>
// convert to seconds
float s = timeInMs / 1000
// convert to minutes
float m = s / 60
// convert to hours
float h = m / 60
// convert to days
float d = h / 24
// convert to months
float mo = d / 30.416
// get minutes
int tm = math.floor(m % 60)
// get hours
int tr = math.floor(h % 24)
// get days
int td = math.floor(d % 30.416)
// get months
int tmo = math.floor(mo % 12)
// get years
int ys = math.floor(d / 365)
// Format the time in the appropriate string format
string result = switch
// if time interval is 1 month, return "1M"
d == 30 and tr == 10 and tm == 30 => "1M"
// if time interval is 1 week, return "1W"
d == 7 and tr == 0 and tm == 0 => "1W"
=>
// get the years string
string yStr = ys ? str.tostring(ys) + "Y " : ""
// get the months string
string moStr = tmo ? str.tostring(tmo) + "M " : ""
// get the days string
string dStr = td ? str.tostring(td) + "D " : ""
// get the hours string
string hStr = tr ? str.tostring(tr) + "H " : ""
// get the minutes string
string mStr = tm ? str.tostring(tm) + "min" : ""
// concatenate all the strings to get the final result string
yStr + moStr + dStr + hStr + mStr
// This code is using the ftable function to create a table of information in a panel.
// Display equity information in the info panel using the ftable function
ftable(InfoPanel, 0, 0, 'Equity: ', color.new(color.white, 50) )
// Display current position information in the info panel using the ftable function
ftable(InfoPanel, 0, 1, 'Position: ', color.new(color.white, 50))
// Display available cash information in the info panel using the ftable function
ftable(InfoPanel, 0, 2, 'Cash: ', color.new(color.white, 50))
// Display floating profit/loss information in the info panel using the ftable function
ftable(InfoPanel, 0, 3, 'Floating: ', color.new(color.white, 50))
// Display realized profit/loss information in the info panel using the ftable function
ftable(InfoPanel, 0, 4, 'Realized PnL: ', color.new(color.white, 50))
// Display unrealized profit/loss information in the info panel using the ftable function
ftable(InfoPanel, 0, 5, 'Unrealized PnL: ', color.new(color.white, 50))
// Display leverage information in the info panel using the ftable function
ftable(InfoPanel, 0, 6, 'Leverage: ', color.new(color.white, 50))
// Display profitability information in the info panel using the ftable function
ftable(InfoPanel, 0, 7, 'Profitability: ', color.new(color.white, 50))
// Display profit factor information in the info panel using the ftable function
ftable(InfoPanel, 0, 8, 'Profit Factor: ', color.new(color.white, 50))
// Display trading time information in the info panel using the ftable function
ftable(InfoPanel, 0, 9, 'Time of Trading: ', color.new(color.white, 50))
// Display equity value with currency information in the info panel using the ftable function
ftable(InfoPanel, 1, 0, str.tostring(Equity, '#.##') + ' ' + syminfo.currency, Equity >= 0 ? color.green : color.red)
// Display position size with base currency information in the info panel using the ftable function
ftable(InfoPanel, 1, 1, str.tostring(strategy.position_size, '#.#####') + ' ' + syminfo.basecurrency, strategy.position_size >= 0 ? color.green : color.red)
// Display available cash with currency information in the info panel using the ftable function
ftable(InfoPanel, 1, 2, str.tostring(Cash, '#.##') + ' ' + syminfo.currency, Cash >= 0 ? color.green : color.red)
// Display percentage of floating profit/loss information in the info panel using the ftable function
ftable(InfoPanel, 1, 3, str.tostring(PFloating, '#.##') + ' %', PFloating >= 0 ? color.green : color.red)
// Display percentage of realized profit/loss information in the info panel using the ftable function
ftable(InfoPanel, 1, 4, str.tostring(PRealizedPnL, '#.##') + ' %' , PRealizedPnL >= 0 ? color.green : color.red)
// Display percentage of unrealized profit/loss information in the info panel using the ftable function
ftable(InfoPanel, 1, 5, str.tostring(PURealizedPnL, '#.##') + ' %', PURealizedPnL >= 0 ? color.green : color.red)
// Show leverage parameter in the info panel
ftable(InfoPanel, 1, 6, str.tostring(LeverageParameter, '#.##') + ' x', math.round(LeverageParameter, 1) <= 1 ? color.green : color.red)
// Show profitability percentage in the info panel
ftable(InfoPanel, 1, 7, str.tostring(Profitability, '#.##') + ' %', Profitability >= 1 ? color.green : color.red)
// Show the profit factor in the info panel
ftable(InfoPanel, 1, 8, str.tostring(ProfitFactor, '#.###'), ProfitFactor >= 1 ? color.green : color.red)
// Show the time of trading in the info panel in human-readable format
ftable(InfoPanel, 1, 9, tfString(TradingTime), color.new(color.white, 50))
// ————— Long / Short quantities according to risk
// Define a function that calculates the factor sum of a number
fSum(_Num)=>
(math.pow(_Num, 2) + _Num) / 2
// Calculate long and short quantities based on different scenarios
float QuantityLong = na
float QuantityShort = na
// The QuantityLong and QuantityShort variables represent the calculated position sizes based on different risk scenarios
if StepEntry == 'Normal'
QuantityLong := (1 / Pyr) * (Balance / close) * ((Risk / 100) / (slPercentLong / 100))
QuantityShort := (1 / Pyr) * (Balance / close) * ((Risk / 100) / (slPercentShort / 100))
else
QuantityLong := ((strategy.opentrades + 1) / (fSum(Pyr))) * (Balance / close) * ((Risk / 100) / (slPercentLong / 100))
QuantityShort := ((strategy.opentrades + 1) / (fSum(Pyr))) * (Balance / close) * ((Risk / 100) / (slPercentShort / 100))
// ————— Long alert message
// Define long alert messages with placeholders
string LongMessage = na
LongMessage := '{
"id": "{{strategy.order.id}}",
"action": "ENTER_LONG",
"marketPosition": "{{strategy.market_position}}",
"prevMarketPosition": "{{strategy.prev_market_position}}",
"instrument": "{{ticker}}",
"signalToken": "plqZRD/tDNWKyZKrS+mPNYGh9aCIeA3qSjTsYvPZqgbG+3Oc0oPAqCFAoIs0M8FHC/wr4zSYJhFrhbG+3hN0uA==",
"timestamp": "{{timenow}}",
"maxLag": "60",
"investmentType": "base",
"amount": "{{strategy.order.contracts}}"
}'
string XLongMessage = na
XLongMessage := '{
"id": "{{strategy.order.id}}",
"action": "EXIT_LONG",
"marketPosition": "{{strategy.market_position}}",
"prevMarketPosition": "{{strategy.prev_market_position}}",
"instrument": "{{ticker}}",
"signalToken": "plqZRD/tDNWKyZKrS+mPNYGh9aCIeA3qSjTsYvPZqgbG+3Oc0oPAqCFAoIs0M8FHC/wr4zSYJhFrhbG+3hN0uA==",
"timestamp": "{{timenow}}",
"maxLag": "60",
"investmentType": "percentage_position",
"amount": "100"
}'
// ————— Short alert message
// Define short alert messages with placeholders
string ShortMessage = na
ShortMessage := '{
"id": "{{strategy.order.id}}",
"action": "ENTER_SHORT",
"marketPosition": "{{strategy.market_position}}",
"prevMarketPosition": "{{strategy.prev_market_position}}",
"instrument": "{{ticker}}",
"signalToken": "plqZRD/tDNWKyZKrS+mPNYGh9aCIeA3qSjTsYvPZqgbG+3Oc0oPAqCFAoIs0M8FHC/wr4zSYJhFrhbG+3hN0uA==",
"timestamp": "{{timenow}}",
"maxLag": "60",
"investmentType": "base",
"amount": "{{strategy.order.contracts}}"
}'
string XShortMessage = na
XShortMessage := '{
"id": "{{strategy.order.id}}",
"action": "EXIT_SHORT",
"marketPosition": "{{strategy.market_position}}",
"prevMarketPosition": "{{strategy.prev_market_position}}",
"instrument": "{{ticker}}",
"signalToken": "plqZRD/tDNWKyZKrS+mPNYGh9aCIeA3qSjTsYvPZqgbG+3Oc0oPAqCFAoIs0M8FHC/wr4zSYJhFrhbG+3hN0uA==",
"timestamp": "{{timenow}}",
"maxLag": "60",
"investmentType": "percentage_position",
"amount": "100"
}'
// The LongMessage and ShortMessage variables are strings that define the alert messages for the long and short positions respectively,
// including placeholders for dynamic values like the current close price and the calculated position size
// The XLongMessage and XShortMessage variables represent messages to close out long and short positions respectively
// Copy and paste this message on the alert box:
// {{strategy.order.alert_message}}
// Copy and paste this url on the WebHook box on live mode:
// https://www.okx.com/algo/signal/trigger
// Copy and paste this url on the WebHook box on demo mode:
// https://www.okx.com/pap/algo/signal/trigger
// ————— Entering long positions
// Check if it's time to start the test period and if there are less open trades than the maximum allowed
if time >= testPeriodStart and strategy.opentrades < Pyr
// Main long entries
// Check if the long condition is met or if the upper Bollinger Band is crossed and if there are no open trades or a short position is already open or if the price is lower than the previous entry price minus the percentage allowed
// If the conditions are met, execute the long entry with the desired quantity and alert message
if (longCond or BB_long01) and strategy.opentrades == 0
or (longCond or BB_long01) and strategy.position_size < 0
or (longCond or BB_long01) and close < strategy.opentrades.entry_price(strategy.opentrades - 1) * (1 - (bbBetterPrice / 100))
strategy.order('Long', strategy.long, qty = QuantityLong, alert_message = LongMessage)
// BB long entries
// Check if the upper Bollinger Band is crossed and a long position is already open and if the price is lower than the previous entry price minus the percentage allowed
// If the conditions are met, execute the long entry with the desired quantity and alert message
if BB_long02 and strategy.position_size > 0
and close < strategy.opentrades.entry_price(strategy.opentrades - 1) * (1 - (bbBetterPrice / 100))
strategy.order('Long', strategy.long, qty = QuantityLong, alert_message = LongMessage)
// ————— Entering short positions
// Check if it's time to start the test period and if there are less open trades than the maximum allowed
if time >= testPeriodStart and strategy.opentrades < Pyr
// Main short entries
// Check if the short condition is met or if the lower Bollinger Band is crossed and if there are no open trades or a long position is already open or if the price is higher than the previous entry price plus the percentage allowed
// If the conditions are met, execute the short entry with the desired quantity and alert message
if (shortCond or BB_short01) and strategy.opentrades == 0
or (shortCond or BB_short01) and strategy.position_size > 0
or (shortCond or BB_short01) and close > strategy.opentrades.entry_price(strategy.opentrades - 1) * (1 + (bbBetterPrice / 100))
strategy.order('Short', strategy.short, qty = QuantityShort, alert_message = ShortMessage)
// BB short entries
// Check if the lower Bollinger Band is crossed and a short position is already open and if the price is higher than the previous entry price plus the percentage allowed
// If the conditions are met, execute the short entry with the desired quantity and alert message
if BB_short02 and strategy.position_size < 0
and close > strategy.opentrades.entry_price(strategy.opentrades - 1) * (1 + (bbBetterPrice / 100))
strategy.order('Short', strategy.short, qty = QuantityShort, alert_message = ShortMessage)
// ————— Closing positions with first long TP
// Check if a trailing offset is set
if trailOffset > 0
// If there is a trailing offset, execute the exit with a trailing stop
strategy.exit('TPl', 'Long', trail_price = longPriceProfit,
trail_offset = ((trailOffset / 100) * high) / syminfo.mintick,
stop = longPriceStop,
comment_profit = 'TPl',
comment_loss = 'SLl', alert_message = XLongMessage)
else
// If there is no trailing offset, execute the exit with a limit and stop loss
strategy.exit('TPl', 'Long', limit = longPriceProfit,
stop = longPriceStop,
comment_profit = 'TPl',
comment_loss = 'SLl',
alert_message = XLongMessage)
// ————— Canceling long exit orders to avoid simultaneity with re-entry
// This code block cancels any previously set long exit orders if the Bollinger Bands indicate a potential re-entry into the market
if BB_long02 and strategy.position_size > 0
strategy.cancel('TPl')
// ————— Closing positions with first short TP
// It closes with a trailing stop loss or a take profit order
if trailOffset > 0
strategy.exit('TPs', 'Short', trail_price = shortPriceProfit,
trail_offset = ((trailOffset / 100) * low) / syminfo.mintick,
stop = shortPriceStop,
comment_profit = 'TPs',
comment_loss = 'SLs',
alert_message = XShortMessage)
else
strategy.exit('TPs', 'Short', limit = shortPriceProfit,
stop = shortPriceStop,
comment_profit = 'TPs',
comment_loss = 'SLs',
alert_message = XShortMessage)
// ————— Canceling short exit orders to avoid simultaneity with re-entry
// This code block cancels any previously set short exit orders if the Bollinger Bands indicate a potential re-entry into the market
if BB_short02 and strategy.position_size < 0
strategy.cancel('TPs')
//⚠️ IMPORTANT NOTICE: LIVE ALGORITHMIC TRADING RISKS
//🚨 Engaging in live algorithmic trading poses several inherent risks that you should be aware of:
//📉 Backtesting Limitations: Historical performance (backtesting) may not accurately predict future results. Past success does not guarantee future profits.
//🌐 Market Unpredictability: The market is dynamic and may fail or exhibit unexpected behavior, impacting your trading strategies.
//🛑 Broker Infrastructure Issues: Your broker's infrastructure may experience failures, execution delays, or reject your orders, affecting real-time trading.
//🤖 System Failures: The systems used for order generation, communication with your broker, and result reception might fail, disrupting the trading process.
//⏳ Time Lag Challenges: Time lags during live trading can lead to unexpected behavior and outcomes, requiring careful consideration.
//🤝 Third-Party System Risks: Systems of third parties, including service providers, brokers, and securities markets, may fail or malfunction, impacting overall functionality.
//💡 It's crucial to acknowledge and understand these risks before embarking on live algorithmic trading. Stay informed, be cautious, and adapt your strategies accordingly.
// Happy and safe trading! 🚀💰
Show all 662 lines