資源の読み込みに... 荷物...

アサシン・グリッドB ダイナミック・グリッド・トレーディング戦略

作者: リン・ハーンチャオチャン, 開催日:2024-02-20 10:47:48
タグ:

img

概要

このPineスクリプトは,自動実行とバックテストのためのstrategy.orders() 機能を使用して,TradingView上でグリッド取引戦略をテストし最適化するための強力なフレームワークを提供します.

戦略の論理

この戦略の基本原理は,入口と出口を導く価格レベル層を含むダイナミックグリッドシステムの概念にあります.価格が各グリッドラインを突破すると取引が起動します.

格子幅と比率は,市場変動と取引プロフィールに基づいて調整される. 格子幅と比率は,市場変動と取引プロフィールに基づいて調整される.

この自動化されたグリッドメカニズムを通じて 戦略は両方向の価格変動の機会を活用して 一貫した正の収益を得ることを目指しています

利益 分析

この戦略の主要な利点は以下の通りです.

  1. ダイナミックグリッド: 格子型,幅設定,ピボット解像度が市場の動態に合わせて調整可能

  2. スマートエントリールール: 柔軟な購入オプション,ポジションサイズ設定,傾向に基づく購入量制御.

  3. 戦術出口: ポジションのサイズ化,販売量設定,損失制限による最適化された収益アプローチ.

  4. 汎用的な設定: スポット・トレードまたはマーージン・トレードモードは,さまざまなトレード要件に対応します.

  5. 拡張的な構成可能性: 初期資本,手数料,利回り等を基準に精密に調整

  6. 情報パネル: 決定を深めるために重要なデータの直感的な可視化

リスク分析

機能にもかかわらず,現実の世界での使用には,次のことに関する意識が必要です.

  1. バックテストの制限過去の業績は将来の業績を正確に予測できないかもしれません.

  2. 市場の不確実性: 価格が予想外に変動し,戦略に影響を与えます.

  3. 交換問題:ブローカーシステムの故障は,注文の遅延や拒否を引き起こす可能性があります.

  4. システム障害: 注文生成,通信,受信のプロセスに障害がある.

  5. タイムラグ: ライブ取引の遅延は予期せぬ結果を引き起こす可能性があります.

この戦略を用いたリアルタイム自動取引を行う前に,これらの固有のリスクは評価され,慎重で測定された実行が可能である.

増進 の 機会

可能な最適化には,以下のものがある.

  1. ストップ・ロスの論理を組み込み 極端な動きで損失を制限します

  2. マシン学習を実装して 格子設定を動的に校正する

  3. 傾向予測や決定を強化するためのキーレベルのための量子指標を統合します.

  4. マージンコールリスクを防ぐリスク管理を導入する.

  5. 貿易入口と出口の効率的なタイミングのために時間枠を分析します.

このような改善により バックテストやライブ環境の両方で より高い性能が実現できます

結論

このPineスクリプトは,グリッド方法論をテストし,改良するための強力な基盤を提供します. いくつかの実行遅延にもかかわらず,知的なリスク調整の慎重な適用は,この戦略が金融市場全体で効果的な自動グリッド取引システムとして機能することを可能にします.


/*backtest
start: 2023-02-19 00:00:00
end: 2024-02-01 05:20:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © AssassinsGrid

// Embark on an automated grid-based trading journey with this Pine script tailored for backtesting in TradingView using strategy.orders().
// Whether you're a seasoned trader or new to the world of financial markets, this script is designed to enhance your trading experience across various assets.
// It's essential to note that while powerful, this script may have a slightly delayed execution compared to the original Assassin's Grid due to the nature of strategy.orders() and strategy.close() functions,
// which execute on the following bar after the price crosses the grid.
//
// Key Features:
//
// 📊 Dynamic Grid Configuration: Define the grid type, width, and pivot point resolution to adapt to market dynamics.
//
// 📈 Smart Buy Strategies: Choose from various buy types, set quantities, and control the number of buy positions based on market trends.
//
// 💹 Strategic Selling: Optimize sell strategies with flexible options, including setting quantities, controlling sell positions, and defining loss thresholds.
//
// 🌐 Versatile Trading: Select between spot and margin trading modes, offering flexibility for diverse trading preferences.
//
// ⚙️ Detailed Configuration: Fine-tune your strategy with parameters like initial capital, commission values, margin rates, and more.
//
// 📊 Informative Chart Elements: Visualize critical information with adjustable labels, table size, grid visibility, and an insightful information panel.
//
// Conclusion:
//
// Whether you're a seasoned trader or a trading enthusiast exploring markets beyond cryptocurrencies, this Pine script provides a robust framework for testing and refining your strategies.
// While powerful, be aware that the execution may have a slight delay compared to the original Assassin's Grid.
// Dive into the dynamic world of grid-based trading, explore various configurations, and refine your approach across a spectrum of financial assets. Happy trading! 🚀💰

//@version=5
strategy("Assassin's Grid B",  shorttitle = "AAGG📈", overlay = true, max_labels_count = 500, initial_capital = 10000, default_qty_value = 0, process_orders_on_close = true)

// INPUTS

// Grid parameters
WOption                     = input.string('Geometric (% Fall)',    'Width Type', ['Arithmetic (Price)', 'Geometric (% Sell)', 'Geometric (% Fall)'],  group = "GRID", tooltip = "Select the type of width for the grid:\n\n- Arithmetic (Price): Fixed width in price units, maintaining constant separation on the chart.\n\n- Geometric (% Sell): Width based on a percentage of the sell price, dynamically adjusting grid lines. (Typically between 5-15%)\n\n- Geometric (% Fall): Width based on a percentage of potential market decline from the last sale, helping visualize potential drops. (Usually between 40-80%)")
Width                       = input.float(75,                       'Width Parameter', minval = 0, step = 0.5, group = "GRID", tooltip = "Set the width parameter for the grid. Larger values result in wider grid lines.")
ppPeriod                    = input.string('4W',                    'Pivot Point Resolution', group = "GRID", tooltip = "Set the resolution for the Pivot Point. Type a timeframe that suits your trading style: 'H, D, W, M'")
MARes                       = input.timeframe('D',                  'EMA Resolution', group = "GRID", tooltip = "Set the resolution for the Exponential Moving Average (EMA). Choose a timeframe that suits your analysis.")
MALength                    = input.int(100,                        'MA Length', minval = 1, group = "GRID", tooltip = "Set the length for the Moving Average (MA). This affects the responsiveness of the MA to price changes.")

// Buy
BuyType                     = input.string('Cash / n Buys',         'Buy Type', ['Contracts', 'Cash', '% Cash', 'Cash / n Buys', 'Cash / n Buys +'], group = "BUY", tooltip = "Select the type of buy: \n- Contracts: Specify the number of contracts to buy. \n- Cash: Specify the amount of cash to invest. \n- % Cash: Specify the percentage of available cash to invest. \n- Cash / n Buys: Distribute available cash equally across n buy positions. \n- Cash / n Buys +: Similar to Cash / n Buys, but the quantity on each buy increases proportionally with the buy number.")
BuyQ                        = input.float(10.0,                     'Contracts / Cash / % Cash', minval = 0, group = "BUY", tooltip = "Set the quantity for buy. For 'Contracts' mode, it represents the number of contracts to buy. For 'Cash' and '% Cash' modes, it represents the amount to invest or the percentage of cash to invest, respectively.")
NBuysUp                     = input.int(4,                          'N Buys over MA', minval = 1, maxval = 30, group = "BUY", tooltip = "Set the maximum number of buy positions allowed above the Moving Average (MA). This helps control the number of buys in an uptrend.")
NBuysDown                   = input.int(5,                          'N Buys under MA (Max.)', minval = 1, maxval = 30, group = "BUY", tooltip = "Set the maximum number of buy positions allowed below the Moving Average (MA). This helps control the number of buys in a downtrend.")
LastXtrades                 = input.int(2,                          'Buy all in last Trades', minval = 0, maxval = 10, group = "BUY", tooltip = "Set the number of the most recent buy trades to consider for making a buy decision. For the '% Cash' option only, this setting enables buying all available cash in the last specified number of trades.")

// Sel
SellType                    = input.string('Position / n Sells +',  'Sell Type', ['Contracts', 'Cash', '% Position', 'Position / n Sells', 'Position / n Sells +'], group = "SELL", tooltip = "Select the type of sell: \n- Contracts: Specify the number of contracts to sell. \n- Cash: Specify the amount of cash to disinvest. \n- % Position: Specify the percentage of the position to sell. \n- Position / n Sells: Distribute the position equally across n sell positions. \n- Position / n Sells +: Similar to Position / n Sells, but the quantity on each sell increases proportionally with the sell number.")
SellQ                       = input.float(5.0,                      'Contracts / Cash / % Position', minval = 0, group = "SELL", tooltip = "Set the quantity for sell. For 'Contracts' mode, it represents the number of contracts to sell. For 'Cash' and '% Position' modes, it represents the amount to disinvest or the percentage of the position to sell, respectively.")
NSellsUp                    = input.int(20,                         'N Sells over MA (Max.)', minval = 1, maxval = 30, group = "SELL", tooltip = "Set the maximum number of sell positions allowed above the Moving Average (MA). This helps control the number of sells in an uptrend.")
NSellsDown                  = input.int(4,                          'N Sells under MA', minval = 1, maxval = 30, group = "SELL", tooltip = "Set the maximum number of sell positions allowed below the Moving Average (MA). This helps control the number of sells in a downtrend.")
LossAllowed                 = input.string('Never',                 'Loss Allowed', ['Never', 'Last buy', 'Always'], group = "SELL", tooltip = "Set the loss allowed criteria: \n- Never: No loss allowed for selling. \n- Last buy: Allow selling if the current price is above the price of the last buy. \n- Always: Allow selling at any price.")

// Trading
TradingType                 = input.string('Spot',                  'Trading Type', ['Spot', 'Margin'], group = "TRADING", tooltip = "Select the type of trading: \n- Spot: Regular trading without margin. \n- Margin: Trading with margin, allowing for leveraged positions.")
InitialContracts            = input.float(10.0,                     '% Initial Capital 1st Trade', minval = 1, maxval = 100, group = "TRADING", tooltip = "Set the percentage of the initial capital to be used for the first trade. This determines the position size for the first trade.") / 100
CommissionValue             = input.float(0.1,                      '% Commission Value', minval = 0, maxval = 100, step = 0.1, group = "TRADING", tooltip = "Set the percentage of the trade value to be considered as a commission. This is deducted from the trading capital.") / 100
MarginRate                  = input.float(1.0,                      '% Margin Rate', minval = 0, maxval = 100, step = 0.5, group = "TRADING", tooltip = "Set the percentage of margin rate to be applied. This is relevant only in margin trading scenarios.") / 100
StartDate                   = timestamp('01 Jan 1970 00:00 +000')
testPeriodStart             = input(StartDate,                 'Start of Trading', group = "TRADING", tooltip = "Set the start date for trading. The strategy will start evaluating trades from this date onwards.")
TableSizeInput              = input.string('Small',                 'Table Size', ['Auto', 'Tiny', 'Small', 'Normal', 'Large', 'Huge'], group = "PLOTTING", tooltip = "Set the size of the information table. Choose a size that suits your preference.")
ShowGrid                    = input(true,                           'Level Grid', group = "PLOTTING", tooltip = "Show or hide the level grid on the chart. The grid represents price levels.")
ShowPanel                   = input(false,                           'Information Panel', group = "PLOTTING", tooltip = "Show or hide the information panel on the chart. The panel displays key information about the strategy and current market conditions.")
ShowLiquidationPrice        = input(false,                          'Liquidation Price', group = "PLOTTING", tooltip = "Show or hide the liquidation price on the chart. The liquidation price is the level at which liquidation may occur, if applicable.")

// VARIABLES

// Grid levels on buys
var float _ldown            = na
bool _pb                    = false
bool _buy                   = false

// Grid levels on sells
var float _lup              = na
bool _ps                    = false
bool _sell                  = false

// First Buy
CloseFirstBar               = ta.valuewhen(bar_index == 0, open, 0)
TimeFirstBar                = ta.valuewhen(bar_index == 0, time, 0)
CloseStart                  = ta.valuewhen(time <= testPeriodStart, open, 0)
FirstClose                  = testPeriodStart > TimeFirstBar ? CloseStart : CloseFirstBar
TimeFirstClose              = testPeriodStart > TimeFirstBar ? testPeriodStart : TimeFirstBar

// Buy and Sell prices 
var float FinalBuyPrice     = na
var float FinalSellPrice    = na
var float FinalOpenPrice    = na
var float BuyLimitPrice     = na
var float SellLimitPrice    = na

// Number of trades
var int nBuys               = na
nBuys                       := nz(nBuys[1])
var int nSells              = na
nSells                      := nz(nSells[1])
var int NBuys               = NBuysDown
var int NSells              = NSellsDown

// Quantities
var float BuyQuantity       = 0
var float BuyAmount         = 0
var float SellQuantity      = 0
var float SellAmount        = 0
var float Commission        = 0
var float Gains             = 0
var float Losses            = 0

// Position calculation
var float PositionCash      = 0
var float PositionSize      = 0
var int BarIndex            = 0

// Average Price Calculation
var float AvgPrice          = 0
var float hl2Bar            = 0

// Backtest information
var float Balance           = 500000
var float Equity            = 0
var float RealizedPnL       = 0
var float PRealizedPnL      = 0
var float Floating          = 0
var float PFloating         = 0
var float URealizedPnL      = 0
var float PURealizedPnL     = 0
var float Cash              = Balance
var float Margin            = 0
var float BuyAndHold        = 0
var float PBuyAndHold       = 0
var float CLeverage         = 0
var float LiquidationPrice  = 0
var bool  Liquidation       = false
var float ProfitFactor      = 0
var int TradingTime         = 0

// Fibonacci Pivots level calculation
var float PP                = open

// Information panel
label labelBalance          = na

// Analyzing when the period changes
bool PeriodChange           = false

// Grid with arrays
aDown                       = array.new_float(30)
aUp                         = array.new_float(30)
aBuy                        = array.new_bool(30)
aSell                       = array.new_bool(30)

// Labels size
fTextSize(_SizeInput)=>
    if _SizeInput == 'Auto'
        size.auto
    else if _SizeInput == 'Tiny'
        size.tiny
    else if _SizeInput == 'Small'
        size.small
    else if _SizeInput == 'Normal'
        size.normal
    else if _SizeInput == 'Normal'
        size.normal
    else if _SizeInput == 'Large'
        size.large
    else if _SizeInput == 'Huge'
        size.huge

// Variable reference
var float MaxFinalOpenPrice = FirstClose

// Value of the MA
var float sMAValue          = na

// GRID

// Function to calculate the Width
fWidth(_Width) =>

    // If price is constant
    if WOption == 'Arithmetic (Price)'
        _Width

    // If price is the Max % of the next Sell
    else if WOption == 'Geometric (% Sell)'
        MaxFinalOpenPrice * (_Width / 100)
    
    // If price is a part of the % of the maximum fall
    else if WOption == 'Geometric (% Fall)'
        MaxFinalOpenPrice / NBuysDown * (_Width / 100)
        
// Origin from Rounded Pivot Points or last Sell
fDownGrid(_GridWidth) =>

    if na(FinalOpenPrice)
        FirstClose
    else
        if FinalSellPrice <= PP
            if PositionSize > 0
                if na(FinalBuyPrice)
                    if WOption == 'Arithmetic (Price)'
                        (math.floor(FinalSellPrice / _GridWidth) * _GridWidth) - _GridWidth
                    else
                        FinalSellPrice - _GridWidth
                else
                    FinalBuyPrice - _GridWidth

            else if PositionSize == 0
                if WOption == 'Arithmetic (Price)'
                    (math.floor(PP / _GridWidth) * _GridWidth) - _GridWidth
                else
                    PP
        else
            if na(FinalBuyPrice)
                if WOption == 'Arithmetic (Price)'
                    (math.floor(PP / _GridWidth) * _GridWidth) - _GridWidth
                else
                    if (FinalSellPrice - _GridWidth) > PP
                        PP
                    else
                        (FinalSellPrice - _GridWidth)
            else
                FinalBuyPrice - _GridWidth
        
// Origin for sells from Rounded Position Price
fUpGrid(_GridWidth) =>
    
    if na(FinalSellPrice)
        if LossAllowed == 'Never'
            if WOption == 'Arithmetic (Price)'
                math.ceil(math.max(AvgPrice, (FinalBuyPrice + _GridWidth)) / _GridWidth) * _GridWidth
            else
                math.max(AvgPrice, (FinalBuyPrice + _GridWidth))
            
        else if LossAllowed == 'Last buy'
            if nBuys == NBuys
                FinalBuyPrice + _GridWidth
            else
                if WOption == 'Arithmetic (Price)'
                    math.ceil(math.max(AvgPrice, (FinalBuyPrice + _GridWidth)) / _GridWidth) * _GridWidth
                else
                    math.max(AvgPrice, (FinalBuyPrice + _GridWidth))
                
        else if LossAllowed == 'Always'
            FinalBuyPrice + _GridWidth
                
    else
        FinalSellPrice + _GridWidth
    
// FUNCTIONS

// Function to sum factorial
fSum(_Num)=>
    (math.pow(_Num, 2) + _Num) / 2

// Function when "Cash / n Buys" or "Position / n Sells"
fCaPo_N(_N, _n) =>
    1 / (_N - nz(_n))

// Function when "Cash / n Buys +" or "Position / n Sells +"
fCaPo_Nplus(_OnSells, _N, _n) =>
    if TradingType == 'Spot' or _OnSells == 1
        (nz(_n)+1) / (fSum(_N) - fSum(nz(_n)))
    else
        (nz(_n)+1) / fSum(_N)
        
// One of the correct ways to use security
f_security(_sym, _res, _src, _rep) => 
    request.security(_sym, _res, _src[not _rep and barstate.isrealtime ? 1 : 0])[_rep or barstate.isrealtime ? 0 : 1]

// Pivot points
PP          := f_security(syminfo.tickerid, ppPeriod, hlc3, false)

// Moving Average
MA          = ta.ema(close, MALength)
sMA         = f_security(syminfo.tickerid, MARes, MA, false)

// Analyzing when the period changes
PeriodChange := ta.change(time(ppPeriod)) != 0

// On Bullish trend, less Number of Buys and more amounts per trade;
// on Bearish more Number of Buys and less amounts per trade
// Max. number of buys
NBuys := if (BuyType == "Cash / n Buys" or BuyType == "Cash / n Buys +")
    if BuyLimitPrice >= sMAValue
        NBuysUp
    else
        NBuysDown
else
    NBuysDown

// On Bullish trend, more Number of Sells and less amounts per trade;
// on Bearish less Number of Sells and more amounts per trade
// Max. number of sells
NSells := if (SellType == "Position / n Sells" or SellType == "Position / n Sells +")
    if SellLimitPrice < sMAValue
        NSellsDown
    else
        NSellsUp
else
    NSellsUp
    
// TRADING

// Start of trading
if time >= TimeFirstClose

    // Final Trade Price, Average Price & Backtest
    for _i = 1 to math.max(NBuys, NSells)
    
        // Grid on Buys
        array.insert(aDown, _i, fDownGrid(fWidth(Width)))
        
        // Crossing between price and levels of grid
        array.insert(aBuy, _i, (low <= array.get(aDown, _i) or open <= array.get(aDown, _i)) and nBuys <= NBuys-1)
        
        // Grid on Sells
        array.insert(aUp, _i, fUpGrid(fWidth(Width)))
    
        // Crossing between price and levels of grid
        array.insert(aSell, _i, (high >= array.get(aUp, _i) or open >= array.get(aUp, _i)) and nSells <= NSells-1)
        strategy.initial_capital = 50000
        // Financial Data
        RealizedPnL         := Balance - strategy.initial_capital
        PRealizedPnL        := (RealizedPnL / strategy.initial_capital) * 100
        Floating            := ((close - AvgPrice) / AvgPrice) * PositionSize * AvgPrice
        PFloating           := (Floating / Balance) * 100
        URealizedPnL        := RealizedPnL + Floating
        PURealizedPnL       := (URealizedPnL / strategy.initial_capital) * 100
        Equity              := Balance + Floating
        Margin              := TradingType == 'Spot' ? 0 : (PositionSize * AvgPrice * MarginRate)
        Cash                := TradingType == 'Spot' ? math.max(0, Balance - (PositionSize * AvgPrice)) : math.max(0, Balance - Margin)
        BuyAndHold          := ((close  - FirstClose) / FirstClose) * strategy.initial_capital
        PBuyAndHold         := (BuyAndHold / strategy.initial_capital) * 100
        CLeverage           := (PositionSize * AvgPrice) / Balance
        LiquidationPrice    := TradingType == 'Spot' ? 0 :  AvgPrice - ((Balance - (Margin * 1)) / PositionSize)
        Liquidation         := (ta.valuewhen(LiquidationPrice >= low, time , 0) <= timenow)
        ProfitFactor        := Gains / Losses
        TradingTime         := timenow - TimeFirstClose
        
        // Quantities to buy according to inputs
        if      BuyType == "Contracts"
            if na(FinalOpenPrice)
                BuyQuantity := ((Cash * InitialContracts) / FirstClose)
            else
                BuyQuantity := math.min((Cash / AvgPrice), BuyQ)
                   
        else if BuyType == "Cash"
            if na(FinalOpenPrice)
                BuyQuantity := (Cash * InitialContracts)
            else
                BuyQuantity := math.min(Cash, BuyQ)
                    
        else if BuyType == "% Cash"
            if na(FinalOpenPrice)
                BuyQuantity := (Cash * InitialContracts)
            else
                if nBuys >= NBuys - LastXtrades
                    BuyQ := (1 / (NBuys - nz(nBuys))) * 100
                
                BuyQuantity := math.min(Cash, (BuyQ / 100) * Cash)
        
        else if BuyType == "Cash / n Buys"
            if na(FinalOpenPrice)
                BuyQuantity := (Cash * InitialContracts)
            else
                BuyQuantity := math.min(Cash, fCaPo_N(NBuys, nBuys) * Cash)
                                           
        else if BuyType == "Cash / n Buys +"
            if na(FinalOpenPrice)
                BuyQuantity := (Cash * InitialContracts)
            else
                BuyQuantity := math.min(Cash, fCaPo_Nplus(0, NBuys, nBuys) * Cash)
            
        // Quantities to sell according to inputs
        if      SellType == "Contracts"
            SellQuantity    := math.min(PositionSize, SellQ)
            
        else if SellType == "Cash"
            SellQuantity    := math.min((PositionSize * AvgPrice), SellQ)
            
        else if SellType == "% Position"
            SellQuantity    := math.min(PositionSize, (SellQ / 100) * PositionSize)
            
        else if SellType == "Position / n Sells"
            SellQuantity    := math.min(PositionSize, fCaPo_N(NSells, nSells) * PositionSize)
        
        else if SellType == "Position / n Sells +"
            SellQuantity    := math.min(PositionSize, fCaPo_Nplus(1, NSells, nSells) * PositionSize)
            
        // First buy limit order from every change of the period
        if (PP != PP[1]) and nz(nBuys) == 0 and not nz(nSells) == 0 and not na(nBuys) and not na(fDownGrid(fWidth(Width)))
            
            // Value of the MA
            sMAValue := sMA
            
            // Buy price of the limit order
            BuyLimitPrice := fDownGrid(fWidth(Width))            
                
        // Buying at better Price
        if array.get(aBuy, _i) and BuyQuantity > 0
            
            // Value of the MA
            sMAValue := sMA
            
            // Price of buy orders and resetting sales
            FinalBuyPrice   := math.min(open, array.get(aDown, _i))
            FinalSellPrice  := na
            FinalOpenPrice  := FinalBuyPrice
            
            // Number of buys and resetting sales
            nBuys           += 1
            nSells          := na
            
            // Redefining buy quantity
            if BuyType == "Contracts"
                BuyAmount   := BuyQuantity
            else
                BuyAmount   := (BuyQuantity / FinalBuyPrice)
            
            // Calculating the priority and secondary price average
            PositionCash    += FinalBuyPrice * BuyAmount
            PositionSize    += BuyAmount
            AvgPrice        := PositionCash / PositionSize
            
            // Calculating net profit
            Balance         -= (BuyAmount * FinalBuyPrice * CommissionValue)
            
            // Comissions losses
            Losses          += (BuyAmount * FinalBuyPrice * CommissionValue)
            
            // Fees paid
            Commission      += (BuyAmount * FinalBuyPrice * CommissionValue)
            
            // Avoiding overlap
            BarIndex        := bar_index            
            
            // Variable reference
            MaxFinalOpenPrice := math.max(FinalBuyPrice, nz(MaxFinalOpenPrice))
            
            // Buy & Sell price of the limit orders
            if nBuys <= NBuys-1
                BuyLimitPrice := FinalBuyPrice - fWidth(Width)
            else
                BuyLimitPrice := na
            
            SellLimitPrice := fUpGrid(fWidth(Width))
            
            // Strategy orders
            strategy.order("Buy", strategy.long, BuyAmount)

            // Buy shapes
            //string BuyText = str.tostring(BuyAmount,'#.####') + "\n" + str.tostring(((BuyAmount * FinalBuyPrice) / Cash) * 100, '#.##') + "%"
            //c_BuyGrad = color.from_gradient(((NBuys - nBuys) / NBuys) * 100, 1, 100, color.lime, color.blue)
            //label.new(bar_index, FinalBuyPrice, BuyText, textcolor = color.new(color.white, 50), color = c_BuyGrad, style = label.style_diamond, size = fTextSize(LabelSizeInput))

        // Selling at better Price    
        else if array.get(aSell, _i) and SellQuantity > 0 and BarIndex != bar_index
            
            // Value of the MA
            sMAValue := sMA
            
            // Price of sale orders and resetting buys
            FinalBuyPrice   := na
            FinalSellPrice  := math.max(open, array.get(aUp, _i))
            FinalOpenPrice  := FinalSellPrice
            
            // Number of sales and resetting buys
            nBuys           := na
            nSells          += 1
            
            // Redefining sell quantity
            if SellType == "Cash"
                SellAmount  := SellQuantity / FinalSellPrice
            else
                SellAmount  := SellQuantity
                
            // Calculating the priority and resetting secondary price average
            PositionCash    -= AvgPrice * SellAmount
            PositionSize    -= SellAmount
            
            // Calculating net profit
            Balance          += (FinalSellPrice - AvgPrice) * SellAmount
            Balance          -= (SellAmount * FinalSellPrice * CommissionValue)
            
            // Gains and Losses
            if FinalSellPrice >= AvgPrice
                Gains       += (FinalSellPrice - AvgPrice) * SellAmount
            else
                Losses      += (AvgPrice - FinalSellPrice) * SellAmount
            
            // Comission losses    
            Losses          += (SellAmount * FinalSellPrice * CommissionValue)
            
            // Fees paid
            Commission      += (SellAmount * FinalSellPrice * CommissionValue)
            
            // Variable reference
            MaxFinalOpenPrice := FinalSellPrice
            
            // Buy & Sell price of the limit orders
            BuyLimitPrice := fDownGrid(fWidth(Width))
            
            if nSells <= NSells-1
                SellLimitPrice := FinalSellPrice + fWidth(Width)
            else
                SellLimitPrice := na

            // Strategy orders
            strategy.close("Buy", comment = 'Sell', qty = SellAmount)

            // Sell shapes
            //string SellText = str.tostring(SellAmount,'#.####') + "\n" + str.tostring((SellAmount / (PositionSize + SellAmount)) * 100, '#.##') + "%"
            //c_SellGrad = color.from_gradient(((NSells - nSells) / NSells) * 100, 1, 100, color.yellow, color.red)
            //label.new(bar_index, FinalSellPrice, SellText, textcolor = color.new(color.white, 50), color = c_SellGrad, style = label.style_diamond, size = fTextSize(LabelSizeInput))
      
// PLOTTING

// Price of the limit orders
bool LastBar = (time >= timenow - (timeframe.multiplier * 1000 * 60))
plotshape(ShowGrid                          ? BuyLimitPrice  : na, "Buy level",  shape.cross, location.absolute, color.new(color.blue, 30), size = size.auto)
plotshape(ShowGrid                          ? SellLimitPrice : na, "Sell level", shape.cross, location.absolute, color.new(color.red,  30), size = size.auto)

// Table
var InfoPanel = table.new(position.middle_left, 2, 12, na, color.new(color.white, 80), 1, color.new(color.white, 80), 1)
ftable(_table_id, _column, _row, _text, _bgcolor) => 
    table.cell(_table_id, _column, _row, _text, 0, 0, _bgcolor, text.align_left, text.align_center, fTextSize(TableSizeInput), na)

tfString(int timeInMs) =>
    // @function  Produces a string corresponding to the input time in days, hours, and minutes.
    // @param     (series int) A time value in milliseconds to be converted to a string variable. 
    // @returns   (string) A string variable reflecting the amount of time from the input time.
    float s  = timeInMs / 1000
    float m  = s / 60
    float h  = m / 60
    float d  = h / 24
    float mo = d / 30.416
    int tm   = math.floor(m % 60)
    int th   = math.floor(h % 24)
    int td   = math.floor(d % 30.416)
    int tmo  = math.floor(mo % 12)
    int ys   = math.floor(d / 365)
    
    string result = 
      switch
        d == 30 and th == 10 and tm == 30 => "1M"
        d == 7  and th == 0  and tm == 0  => "1W"
        =>
            string yStr  = ys  ? str.tostring(ys)  + "Y "  : ""
            string moStr = tmo ? str.tostring(tmo) + "M "  : ""
            string dStr  = td  ? str.tostring(td)  + "D "  : ""
            string hStr  = th  ? str.tostring(th)  + "H "  : ""
            string mStr  = tm  ? str.tostring(tm)  + "min" : ""
            yStr + moStr + dStr + hStr + mStr
            
if ShowPanel
    ftable(InfoPanel, 0, 0,     'Equity: '                                                                              , color.new(color.white, 50))
    ftable(InfoPanel, 0, 1,     'Position: '                                                                            , color.new(color.white, 50))
    ftable(InfoPanel, 0, 2,     'Cash: '                                                                                , color.new(color.white, 50))
    ftable(InfoPanel, 0, 3,     'Margin: '                                                                              , color.new(color.white, 50))
    ftable(InfoPanel, 0, 4,     'Current Leverage: '                                                                    , color.new(color.white, 50))
    ftable(InfoPanel, 0, 5,     'Commission Paid: '                                                                     , color.new(color.white, 50))
    ftable(InfoPanel, 0, 6,     'Floating: '                                                                            , color.new(color.white, 50))
    ftable(InfoPanel, 0, 7,     'Realized PnL: '                                                                        , color.new(color.white, 50))
    ftable(InfoPanel, 0, 8,     'Unrealized PnL: '                                                                      , color.new(color.white, 50))
    ftable(InfoPanel, 0, 9,     'Buy n Hold: '                                                                          , color.new(color.white, 50))
    ftable(InfoPanel, 0, 10,    'Profit Factor: '                                                                       , color.new(color.white, 50))
    ftable(InfoPanel, 0, 11,    'Time of Trading: '                                                                     , color.new(color.white, 50))
    ftable(InfoPanel, 1, 0,     Liquidation ? 'Liquidation' : str.tostring(Equity, '#.####') + ' ' + syminfo.currency   , Liquidation ? color.red : color.green)
    ftable(InfoPanel, 1, 1,     str.tostring(PositionSize, '#.####') + ' ' + syminfo.basecurrency                       , color.green)
    ftable(InfoPanel, 1, 2,     str.tostring(Cash, '#.####') + ' ' + syminfo.currency                                   , color.green)
    ftable(InfoPanel, 1, 3,     str.tostring(Margin, '#.####') + ' ' + syminfo.currency                                 , color.green)
    ftable(InfoPanel, 1, 4,     TradingType == 'Spot' ? 'Spot' : str.tostring(CLeverage, '#.##') + 'x'                  , color.green)
    ftable(InfoPanel, 1, 5,     str.tostring(Commission, '#.####') + ' ' + syminfo.currency                             , Commission    == 0 ? color.green : color.red)
    ftable(InfoPanel, 1, 6,     str.tostring(PFloating, '#.##') + ' %'                                                  , PFloating     >= 0 ? color.green : color.red)
    ftable(InfoPanel, 1, 7,     str.tostring(PRealizedPnL, '#.##') + ' %'                                               , PRealizedPnL  >= 0 ? color.green : color.red)
    ftable(InfoPanel, 1, 8,     str.tostring(PURealizedPnL, '#.##') + ' %'                                              , PURealizedPnL >= 0 ? color.green : color.red)
    ftable(InfoPanel, 1, 9,     str.tostring(PBuyAndHold, '#.##') + ' %'                                                , PBuyAndHold   >= 0 ? color.green : color.red)
    ftable(InfoPanel, 1, 10,    str.tostring(ProfitFactor, '#.##')                                                      , ProfitFactor  >= 1 ? color.green : color.red)
    ftable(InfoPanel, 1, 11,    tfString(TradingTime)                                                                   , color.new(color.white, 50))
    
// Plotting pivot points
plot(PP, title = "PP", style = plot.style_stepline, color = color.silver, linewidth = 1)

// Plotting the average price
plotshape(barstate.isrealtime and ta.change(AvgPrice)     != 0                     ? AvgPrice       : na, "AvgPricepr",   shape.diamond, location.absolute, color.new(color.yellow,  10), size = size.tiny)
plotshape(                        ta.change(AvgPrice[1])  != 0                     ? AvgPrice[1]    : na, "AvgPricep",    shape.diamond, location.absolute, color.new(color.yellow,  40), size = size.tiny)
plotshape(TimeFirstClose == time                                                   ? FirstClose     : na, "FirstClose",   shape.diamond, location.absolute, color.new(color.yellow,  40), size = size.tiny)

// Plotting the moving average
plot((BuyType == "Cash / n Buys" or BuyType == "Cash / n Buys +") and NBuysUp != NBuysDown ? sMA : na, title = "Moving Average Buys", color = color.new(color.blue, 50), linewidth = 2)
plot((SellType == "Position / n Sells" or SellType == "Position / n Sells +") and NSellsUp != NSellsDown ? sMA : na, title = "Moving Average Sells", color = color.new(color.red, 50), linewidth = 2)

// Plotting the liquidation price
plot(ShowLiquidationPrice and LiquidationPrice > 0 ? LiquidationPrice : na, "Liquidation Price", Liquidation ? color.new(color.red, 30) : color.new(color.lime, 30), 2)
barcolor(Liquidation ? color.red : na)

//⚠️ 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! 🚀💰

もっと