Pinescript strategy to seasonality

Discussion in 'Strategy Building' started by williamblake72, Jan 13, 2024.

  1. Hi all,
    I am learning Pinescript and I am trying to build a simple strategy that, given in input a start date (day and month) and a window duration, defines a "sensitive area" (e.g. from 15 days before the start to the half of the seasonal window). Then, in this sensitive area it checks if there is a technical pattern (a crossover of the upper BB in this case) and if yes, then enters long.

    It is obviously for learning purposes, I will not trade this.
    The strategy compiles but then when i go to the strategy tester it says that there is no case in which the strategy enters. It seems to me impossible, and i tried with many commodity ETFs such as CORN, USO, WHEAT, UNG etc

    Can you help me to find the mistake? I am trying for instance with these parameters on ETF CORN: 1st of June start, window duration 30 days, entry tolerance 15 days. Technical condition: crossover on the upper Bollinger band

    Here is the code. I havemade a bit alone and a bit with chatGPT support.

    Thanks a lot for your kind support

    ******

    //@version=5
    strategy("Test Seasonality", shorttitle="Test Seasonality", overlay=true)

    // Input
    startDay = input(1, title="Start Day")
    startMonth = input(6, title="Start Month")
    windowDuration = input(30, title="Window Duration")
    entryTolerance = input(15, title="Entry Tolerance")

    // Computation of seasonal window and sensitive window
    seasonalWindowStart = timestamp(year, startMonth, startDay)
    seasonalWindowEnd = seasonalWindowStart + windowDuration
    sensitiveWindowStart = seasonalWindowStart - entryTolerance
    sensitiveWindowEnd = sensitiveWindowStart + windowDuration/2

    // Technical indicator Bollinger Bands
    length = input(20, title="Length")
    mult = input(2, title="Multiplier")
    basis = ta.sma(close, length)
    dev = mult * ta.stdev(close, length)

    // Technical pattern
    techCondition = close[1] < basis[1] - dev[1] and close > basis - dev

    // Check if there are open positions
    openTrades = strategy.opentrades

    // Entry condition
    longCondition = (techCondition) and time >= sensitiveWindowStart and time <= sensitiveWindowEnd

    // Exit conditions
    seasonalWindowExpired = time >= seasonalWindowEnd

    // Strategy logic
    if (longCondition and openTrades == 0)
    strategy.entry("Long", strategy.long)
    if (seasonalWindowExpired)
    strategy.close("Long")
     
  2. Take with grain of salt, but here is a "potential" code to test (with AI support). Here are some notes:
    potential issues that might be causing the strategy not to enter any trades.

    1. Date Handling:
      • The calculation for seasonalWindowEnd does not convert the window duration from days to milliseconds. Pine Script timestamps are in milliseconds, so you need to multiply the window duration by the number of milliseconds in a day.
      • Similarly, sensitiveWindowEnd needs to consider the milliseconds conversion for the half window duration.
    2. Technical Condition for Bollinger Bands:
      • The condition techCondition = close[1] < basis[1] - dev[1] and close > basis - dev is checking if the previous close is below the lower Bollinger Band and the current close is above the lower Bollinger Band. This does not match the description of checking for a crossover of the upper Bollinger Band. The condition needs to be adjusted to reflect the upper band crossover.
    3. Time Comparisons:
      • Ensure that the time variable, which represents the bar's time, is correctly compared with sensitiveWindowStart and sensitiveWindowEnd. Sometimes, time zone differences or the way TradingView handles timestamps can lead to unexpected results.
    4. Strategy Entry Logic:
      • The entry logic seems to be correct as long as the conditions are met. However, make sure that the openTrades == 0 condition is not preventing entries in a way you didn't intend.
    ---------------------
    //@version=5
    strategy("Test Seasonality", shorttitle="Test Seasonality", overlay=true)

    // Input
    startDay = input(1, title="Start Day")
    startMonth = input(6, title="Start Month")
    windowDuration = input(30, title="Window Duration")
    entryTolerance = input(15, title="Entry Tolerance")

    // Computation of seasonal window and sensitive window
    seasonalWindowStart = timestamp(year, startMonth, startDay)
    seasonalWindowEnd = seasonalWindowStart + windowDuration * 86400000 // Convert days to milliseconds
    sensitiveWindowStart = seasonalWindowStart - entryTolerance * 86400000 // Convert days to milliseconds
    sensitiveWindowEnd = sensitiveWindowStart + windowDuration * 86400000 / 2 // Convert days to milliseconds

    // Technical indicator Bollinger Bands
    length = input(20, title="Length")
    mult = input(2, title="Multiplier")
    basis = ta.sma(close, length)
    dev = mult * ta.stdev(close, length)
    upperBB = basis + dev
    lowerBB = basis - dev

    // Technical pattern for crossover on the upper Bollinger band
    techCondition = close[1] < upperBB[1] and close > upperBB

    // Check if there are open positions
    openTrades = strategy.opentrades

    // Entry condition
    longCondition = (techCondition) and time >= sensitiveWindowStart and time <= sensitiveWindowEnd

    // Exit conditions
    seasonalWindowExpired = time >= seasonalWindowEnd

    // Strategy logic
    if (longCondition and openTrades == 0)
    strategy.entry("Long", strategy.long)
    if (seasonalWindowExpired)
    strategy.close("Long")
     
    Last edited: Jan 13, 2024
  3. Thanks, i think the main issue was due to the milliseconds topic (i am newbie in pinescript and I did not know this!). Now it seems to work, at least giving almost 1 entry and 1 exit every year based on the technical condition.

    I have updated the code to work also on futures. Now i have the last issue which is that stopLoss is not working. For instance applied to CL1! in 2022 i have a loss of -30k$, while I should have close to stop loss value. Ho is possible to maange stop loss in a strategy in pinescript? Thanks in advance!

    ************

    //@version=5
    strategy("Test Seasonality Commodities", shorttitle="Test Seasonality", overlay=true)

    // Input
    startDay = input(1, title="Start Day")
    startMonth = input(2, title="Start Month")
    windowDuration = input(60, title="Window Duration")
    entryTolerance = input(15, title="Entry Tolerance")
    maxLossAmount = input(2000, title="Stop Loss Amount ($)")

    // Computation of seasonal window and sensitive window
    seasonalWindowStart = timestamp(year, startMonth, startDay)
    seasonalWindowEnd = seasonalWindowStart + windowDuration * 86400000 // Convert days to milliseconds
    sensitiveWindowStart = seasonalWindowStart - entryTolerance * 86400000 // Convert days to milliseconds
    sensitiveWindowEnd = sensitiveWindowStart + windowDuration * 86400000 / 2 // Convert days to milliseconds

    // Define the continuous back-adjusted futures symbol
    continuousFuturesClose = request.security(syminfo.tickerid, "D", close)

    // Technical indicator Bollinger Bands
    length = input(20, title="Length")
    mult = input(2, title="Multiplier")
    basis = ta.sma(continuousFuturesClose, length)
    dev = mult * ta.stdev(continuousFuturesClose, length)
    upperBB = basis + dev
    lowerBB = basis - dev

    // Check if there are open positions
    openTrades = strategy.opentrades

    // Entry condition
    longCondition = (ta.crossover(close, upperBB) or ta.crossover(close, lowerBB)) and time >= sensitiveWindowStart and time <= sensitiveWindowEnd

    // Calculate potential loss
    potentialLoss = close - strategy.position_avg_price

    // Stop-loss condition based on maximum loss amount
    stopLossCondition = potentialLoss < -maxLossAmount

    // Exit conditions
    seasonalWindowExpired = time >= seasonalWindowEnd

    // Strategy logic
    if (longCondition and openTrades == 0)
    strategy.entry("Long", strategy.long)

    if (stopLossCondition or seasonalWindowExpired)
    strategy.close("Long", comment=stopLossCondition ? "Stop Loss" : "End of Seasonality")
     
    Last edited: Jan 13, 2024
  4. An assisted, response:
    The provided Pine Script code aims to include a stop-loss mechanism based on a fixed dollar amount (maxLossAmount). However, there seems to be an issue in how the stop-loss condition is calculated and executed. Let's address this to ensure the stop-loss works as intended.

    1. Stop-Loss Calculation:
      • The current calculation of potentialLoss as close - strategy.position_avg_price is correct for determining the loss per share/contract since the position was opened.
      • However, to implement a stop-loss based on a total dollar amount, you need to consider the position size (number of shares/contracts) as well.
    2. Implementing Dollar-Based Stop-Loss:
      • To implement a dollar-based stop-loss in Pine Script, you need to translate the dollar amount into a price level at which the stop-loss should trigger.
      • This involves calculating the price level that, if reached, would result in a total loss equal to maxLossAmount.
    3. Correcting Stop-Loss Logic:
      • Your current stop-loss logic triggers when the unrealized loss per share/contract exceeds the negative maxLossAmount, which is not the intended behavior for a dollar-based stop-loss.
      • Instead, calculate the stop-loss price level and check if the current price has reached or crossed this level.
    Let's modify your code to include a correct dollar-based stop-loss mechanism:
    //@version=5
    strategy("Test Seasonality Commodities", shorttitle="Test Seasonality", overlay=true)

    // ... [Previous code remains unchanged]

    // Stop-loss calculation
    stopLossPriceLevel = strategy.position_avg_price - (maxLossAmount / strategy.position_size)

    // Stop-loss condition based on price level
    stopLossCondition = close <= stopLossPriceLevel

    // ... [Rest of the strategy logic]

    if (longCondition and openTrades == 0)
    strategy.entry("Long", strategy.long)

    if (stopLossCondition or seasonalWindowExpired)
    strategy.close("Long", comment=stopLossCondition ? "Stop Loss" : "End of Seasonality")
    -----------------------------
    In this modification:

    • stopLossPriceLevel calculates the price level at which the total loss would equal maxLossAmount.
    • The stopLossCondition is now based on whether the current close price has fallen to or below this price level.
    Remember, this logic assumes a long position. If you also have short positions, you need to adjust the logic accordingly. Also, ensure that strategy.position_size and strategy.position_avg_price are valid and contain expected values, especially when dealing with futures contracts.

    Test this modified script thoroughly to ensure it behaves as expected, especially under different market conditions and with various parameter settings.
     
  5. Thanks for your help! I managed to solve with some youtube video and examples! May I ask which AI are you using? Do you have any good Pinescript course to suggest to me (Udemy, etc)?
     
  6. I have no experience with Pinescript, and since your questions were so well worded and clear, I just passed them to Chat-GPT4.
     
  7. Thus, may be I am using a outdated version of chat GPT :) thanks
     
  8. I have a subscription for chat-gpt4. So far, am pleased.