TLDR: I am trying to write a study that uses a state variable to transfer information from one bar to the next, but can't manage to understand why it fails, returning N/A values for the state variable (and obviously an empty plot). I suspect the issue is related to separating the variable definition from its value assignment.
While the implementation of a state variable is a trivial construction in many programming languages, it is challenging in ThinkScript due the constraint that forbids intrabar variable updates. This led me to the implementation shown in the pseudocode below
On bar 1 state is set equal to zero. Despite nextState not being used by the CompoundValue function on bar 1, the thinkScript editor requires it to be defined, which is the reason why I had to add the def nextState statement on top, that is well before the value of nextState gets assigned on the last instruction of the routine.
According to the reference manual this is a legal construct in ThinkScript, if the value is assigned before the variable gets used. This is indeed the case as the routine goes on computing quantities and conditions based on the value of state and finally ends up the execution for bar 1 by assigning to nextState its computed value. This value will then be used for the first time at the beginning of bar 2 when the CompoundValue function assigns it to state.
As mentioned earlier, the study fails returning N/A values for both state and nextState, resulting in empty plots. The suspicion that the failure is related to the separate definition and value assignment of nextState is heightened by the fact that when I eliminate it from the arguments of CompoundValue, writing for example something like
def state = CompoundValue(1, state[1]+1, 0);
then state gets plotted without any problem.
I cannot see in which way my code might violate the syntax described in the ThinkScript manual, and I would appreciate if someone could point that out or maybe let me know whether I am running into some known issue.
To fully illustrate the issue, I attached below a simplified study that reproduces it. This study is meant to run concurrently to a strategy that can either open a long or a short position, under the constraint that at any time there cannot be more than one open position, which, hence, needs to be closed before any other trade can take place. While in the strategy this constraint is handled automatically by using the appropriate OrderType (BUY_TO_OPEN, SELL_AUTO, SELL_TO_CLOSE, SELL_TO_OPEN), in a study a state variable is needed to greenlight only those trade that are allowed in a given state.
While the implementation of a state variable is a trivial construction in many programming languages, it is challenging in ThinkScript due the constraint that forbids intrabar variable updates. This led me to the implementation shown in the pseudocode below
Code:
#Begin of the study
def nextState;
def state = CompoundValue(1, nextState[1], 0);
..........................................
# series of computations of quantities and conditions based on the value of state
.............................
plot statePlot = state;
#last instruction computes the state variable for next bar
nextState = function(state);
On bar 1 state is set equal to zero. Despite nextState not being used by the CompoundValue function on bar 1, the thinkScript editor requires it to be defined, which is the reason why I had to add the def nextState statement on top, that is well before the value of nextState gets assigned on the last instruction of the routine.
According to the reference manual this is a legal construct in ThinkScript, if the value is assigned before the variable gets used. This is indeed the case as the routine goes on computing quantities and conditions based on the value of state and finally ends up the execution for bar 1 by assigning to nextState its computed value. This value will then be used for the first time at the beginning of bar 2 when the CompoundValue function assigns it to state.
As mentioned earlier, the study fails returning N/A values for both state and nextState, resulting in empty plots. The suspicion that the failure is related to the separate definition and value assignment of nextState is heightened by the fact that when I eliminate it from the arguments of CompoundValue, writing for example something like
def state = CompoundValue(1, state[1]+1, 0);
then state gets plotted without any problem.
I cannot see in which way my code might violate the syntax described in the ThinkScript manual, and I would appreciate if someone could point that out or maybe let me know whether I am running into some known issue.
To fully illustrate the issue, I attached below a simplified study that reproduces it. This study is meant to run concurrently to a strategy that can either open a long or a short position, under the constraint that at any time there cannot be more than one open position, which, hence, needs to be closed before any other trade can take place. While in the strategy this constraint is handled automatically by using the appropriate OrderType (BUY_TO_OPEN, SELL_AUTO, SELL_TO_CLOSE, SELL_TO_OPEN), in a study a state variable is needed to greenlight only those trade that are allowed in a given state.
Code:
# ==========================================
# ThinkScript study that monitors 4 boolean variables that signal the conditions to enter/exit a long or a short position .
# Constraint: At all times there cannot be more than one open position
# Entry into a long (short) position is triggered by the boolean longEntry (shortEntry), which is true when the fast MA crosses above (below) the slow MA AND the latter is increasing decreasing)
# Exit from a long (short) position is triggered by longExit (shortExit) which is true when either the fast MA is below (above) the slow MA OR the latter is decreasing (increasing) for as many consecutive bars as specified by exitBars.
# The variable state represents the current open position and determines what trades are feasible in that situatio: if there is no open position (state = 0), both longEntry and shortEntry are valid trade triggers, if there is an open long position (state = 1), only exitLong is a valid trade trigger, if there is an open short position (state = -1) only exitShort is a valid trade trigger
# ==========================================
declare lower;
input fastLen = 3;
input slowLen = 60;
input exitBars = 6;
input price = open;
def fastMA = Average(price, 3);
def slowMA = Average(price, 60);
def slowSlope = slowMA - slowMA[1];
def slowGrowing = slowSlope > 0;
def slowFalling = slowSlope < 0;
def crossUp = fastMA crosses above slowMA;
def crossDown = fastMA crosses below slowMA;
#############################################################
# ----------------------------
# state variable (stable this bar)
# ----------------------------
def nextState;
def state = CompoundValue(1, nextState[1], 0); # State is x(n), nextState is x(n+1)
def isFlat = state == 0;
def inLong = state == 1;
def inShort = state == -1;
# To compute valid Entries/exits use state x(n)
#Long Entry points
def longEntry = isFlat and crossUp and slowGrowing;
#Short Entry points
def shortEntry = isFlat and crossDown and slowFalling;
# Exit points
def longFail = inLong and (fastMA < slowMA or slowFalling);
def shortFail = inShort and (fastMA > slowMA or slowGrowing);
# Counts must also be CompoundValue (safer) and must reset when not in that position
def longFailCount = CompoundValue(
1,
if !inLong then 0 else if longFail then longFailCount[1] + 1 else 0,
0
);
def shortFailCount = CompoundValue(
1,
if !inShort then 0 else if shortFail then shortFailCount[1] + 1 else 0,
0
);
#Long Exit points
def longExit = longFailCount >= exitBars;
#Short Exit points
def shortExit = shortFailCount >= exitBars;
# ----------------------------
# Computation of nextState
# ----------------------------
nextState =
if longExit then 0
else if shortExit then 0
else if longEntry then 1
else if shortEntry then -1
else state;
# The value on nextState in bar n becomesthe value of state in bar n+1
#Plot the state with the transition shown in the bar and entry/exit happened
plot statePlot = state;
statePlot.SetDefaultColor(Color.BLUE);
plot nextStatePlot = nextState;
nextStatePlot.SetDefaultColor(Color.RED);