Cette stratégie utilise la méthode de négociation de la grille dans la théorie des océans pour placer des ordres d'achat et de vente dans une plage de prix prédéfinie.
La stratégie calcule d'abord les limites supérieures et inférieures de la grille de prix en fonction du choix de l'utilisateur ou des paramètres par défaut. Il existe deux façons de calcul: obtenir les prix les plus élevés et les plus bas de la période de backtesting, ou calculer des moyennes mobiles sur une période de temps. Ensuite, les lignes de grille sont uniformément réparties en fonction du nombre de grilles définies par l'utilisateur.
Les signaux de négociation sont générés en fonction de la relation entre le prix et les lignes de grille. Lorsque le prix est en dessous d'une ligne de grille, une position longue est ouverte au prix de la ligne de grille avec une quantité fixe; lorsque le prix dépasse une ligne de grille, la position est fermée à la ligne de grille en dessous. Comme le prix fluctue à l'intérieur de la grille, les positions changent en conséquence pour gagner du profit.
Plus précisément, la stratégie maintient un tableau de prix de ligne de grille et un tableau de bool indiquant si les ordres sont placés à chaque ligne. Lorsque le prix est en dessous d'une ligne sans ordres, une position longue est ouverte à la ligne; lorsque le prix est au-dessus d'une ligne alors que des ordres existent à la ligne ci-dessous, les positions sont fermées à la ligne inférieure.
La plage de grille est calculée automatiquement, évitant ainsi les difficultés de réglage manuel.
Les lignes de grille sont réparties uniformément afin d'éviter les surcharges dues à la densité des grilles.
La méthode de négociation par réseau contrôle efficacement les risques. Le profit peut être réalisé tant que les prix fluctuent dans le réseau.
Aucune hypothèse d'orientation des prix, adaptée au marché à plage.
Commissions et positions personnalisables pour différents instruments de négociation.
La visualisation des lignes de grille aide à comprendre la situation des transactions.
Les risques de rupture des prix, qui peuvent entraîner des pertes plus importantes.
L'excès d'espace réseau présente des risques. Les réseaux trop lâches ne peuvent pas générer de bénéfices facilement, tandis que les réseaux trop étroits augmentent les coûts.
Les risques de détention prolongée.
Risques liés à un mauvais réglage des paramètres: la période de rétro-test ou la période de moyenne mobile peuvent affecter le calcul de la plage de réseau si elles sont définies de manière inappropriée.
Risques de marché systémiques: plus adaptés aux marchés à tendance à long terme que les marchés à plage.
Optimiser les paramètres du réseau. Considérer de manière globale les conditions du marché, les coûts, etc. pour optimiser le nombre de réseaux, la période de réflexion, etc.
Introduire un ajustement dynamique de la plage de réseau. Adapter les plages de réseau lorsque des changements importants se produisent sur le marché.
Incorporer des mécanismes d'arrêt des pertes. Définir des lignes d'arrêt des pertes appropriées pour limiter les pertes. Peut être ajusté dynamiquement.
Ajoutez des filtres utilisant d'autres indicateurs, tels que les bandes de Bollinger, les indicateurs de tendance, etc., pour éviter des transactions incorrectes.
Améliorer l'efficacité de l'utilisation des capitaux.
La stratégie réalise un trading de gamme contrôlable par le risque en tirant parti des principes du trading de la grille. Le calcul automatique de la grille et la distribution uniforme offrent des avantages qui conviennent à divers marchés grâce au réglage des paramètres. Les risques sont limités et faciles à exploiter. Cependant, des limites existent et des améliorations continues sont nécessaires pour s'adapter aux marchés en évolution.
/*backtest start: 2023-09-12 00:00:00 end: 2023-10-12 00:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=4 strategy("(IK) Grid Script", overlay=true, pyramiding=14, close_entries_rule="ANY", default_qty_type=strategy.cash, initial_capital=100.0, currency="USD", commission_type=strategy.commission.percent, commission_value=0.1) i_autoBounds = input(group="Grid Bounds", title="Use Auto Bounds?", defval=true, type=input.bool) // calculate upper and lower bound of the grid automatically? This will theorhetically be less profitable, but will certainly require less attention i_boundSrc = input(group="Grid Bounds", title="(Auto) Bound Source", defval="Hi & Low", options=["Hi & Low", "Average"]) // should bounds of the auto grid be calculated from recent High & Low, or from a Simple Moving Average i_boundLookback = input(group="Grid Bounds", title="(Auto) Bound Lookback", defval=250, type=input.integer, maxval=500, minval=0) // when calculating auto grid bounds, how far back should we look for a High & Low, or what should the length be of our sma i_boundDev = input(group="Grid Bounds", title="(Auto) Bound Deviation", defval=0.10, type=input.float, maxval=1, minval=-1) // if sourcing auto bounds from High & Low, this percentage will (positive) widen or (negative) narrow the bound limits. If sourcing from Average, this is the deviation (up and down) from the sma, and CANNOT be negative. i_upperBound = input(group="Grid Bounds", title="(Manual) Upper Boundry", defval=0.285, type=input.float) // for manual grid bounds only. The upperbound price of your grid i_lowerBound = input(group="Grid Bounds", title="(Manual) Lower Boundry", defval=0.225, type=input.float) // for manual grid bounds only. The lowerbound price of your grid. i_gridQty = input(group="Grid Lines", title="Grid Line Quantity", defval=8, maxval=15, minval=3, type=input.integer) // how many grid lines are in your grid strategy.initial_capital = 50000 f_getGridBounds(_bs, _bl, _bd, _up) => if _bs == "Hi & Low" _up ? highest(close, _bl) * (1 + _bd) : lowest(close, _bl) * (1 - _bd) else avg = sma(close, _bl) _up ? avg * (1 + _bd) : avg * (1 - _bd) f_buildGrid(_lb, _gw, _gq) => gridArr = array.new_float(0) for i=0 to _gq-1 array.push(gridArr, _lb+(_gw*i)) gridArr f_getNearGridLines(_gridArr, _price) => arr = array.new_int(3) for i = 0 to array.size(_gridArr)-1 if array.get(_gridArr, i) > _price array.set(arr, 0, i == array.size(_gridArr)-1 ? i : i+1) array.set(arr, 1, i == 0 ? i : i-1) break arr var upperBound = i_autoBounds ? f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, true) : i_upperBound // upperbound of our grid var lowerBound = i_autoBounds ? f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, false) : i_lowerBound // lowerbound of our grid var gridWidth = (upperBound - lowerBound)/(i_gridQty-1) // space between lines in our grid var gridLineArr = f_buildGrid(lowerBound, gridWidth, i_gridQty) // an array of prices that correspond to our grid lines var orderArr = array.new_bool(i_gridQty, false) // a boolean array that indicates if there is an open order corresponding to each grid line var closeLineArr = f_getNearGridLines(gridLineArr, close) // for plotting purposes - an array of 2 indices that correspond to grid lines near price var nearTopGridLine = array.get(closeLineArr, 0) // for plotting purposes - the index (in our grid line array) of the closest grid line above current price var nearBotGridLine = array.get(closeLineArr, 1) // for plotting purposes - the index (in our grid line array) of the closest grid line below current price for i = 0 to (array.size(gridLineArr) - 1) if close < array.get(gridLineArr, i) and not array.get(orderArr, i) and i < (array.size(gridLineArr) - 1) buyId = i array.set(orderArr, buyId, true) strategy.entry(id=tostring(buyId), long=true, qty=(strategy.initial_capital/(i_gridQty-1))/close, comment="#"+tostring(buyId)) if close > array.get(gridLineArr, i) and i != 0 if array.get(orderArr, i-1) sellId = i-1 array.set(orderArr, sellId, false) strategy.close(id=tostring(sellId), comment="#"+tostring(sellId)) if i_autoBounds upperBound := f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, true) lowerBound := f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, false) gridWidth := (upperBound - lowerBound)/(i_gridQty-1) gridLineArr := f_buildGrid(lowerBound, gridWidth, i_gridQty) closeLineArr := f_getNearGridLines(gridLineArr, close) nearTopGridLine := array.get(closeLineArr, 0) nearBotGridLine := array.get(closeLineArr, 1)