TradeStation EasyLanguage to ThinkScript

sunnyr

New member
VIP
Does anyone know how to convert thinkscript to easylanguage? I was going to attempt this myself but it is taking too long. I am looking to convert around 15 indicators almost all of them are mashups of indicators from here that I have modified to create a successful system scalping TSLA options. Here is my current grid for anyone interested. It is complete however I am working on cutting some fat.

Grid Link: http://tos.mx/k3eswoE
 

Trading51

Active member
2019 Donor
There's a few codes in here could someone convert these, heres the link to the file

http://traders.com/Documentation/FEEDbk_docs/2015/09/TradersTips.html

In “Decyclers” in this issue, author John Ehlers describes a method for constructing an oscillator that can help traders detect trend reversals with almost no lag. Ehlers calls this new oscillator a decycler. The author begins the process by isolating the high-frequency components present in the input data. He then subtracts these from the input data leaving only the lower-frequency components representing the trend.

For convenience, we are providing some EasyLanguage code for the simple decycler and decycler oscillator indicators based on Ehlers’ concepts. In addition, we are providing code for a TradeStation function to calculate the decycler oscillator, and a strategy that demonstrates the function’s usage.

Indicator: Simple Decycler
Code:
// TASC Sep 2015
// Decyclers - John F. Ehlers
// Simple Decyclers

inputs:
    HPPeriod( 125 ) ;
   
variables:
    alpha1( 0 ),
    HP( 0 ),
    Decycle( 0 ) ;
   
// High Pass Filter
alpha1 = ( Cosine ( 0.707 * 360 / HPPeriod ) +
Sine( 0.707 * 360 / HPPeriod ) - 1 )
/ Cosine( .707 * 360 / HPPeriod ) ;

HP = ( 1 - alpha1 / 2 ) * ( 1 - alpha1 / 2 ) *
( Close - 2 * Close[1] + Close[2] ) + 2 *
( 1 - alpha1 ) * HP[1] - ( 1 - Alpha1 ) *
( 1 - alpha1 ) * HP[2] ;       

Decycle = Close - HP ;

Plot1( Decycle, "DeCycle" ) ;
Plot2( 1.005 * Decycle, "UpperBand" ) ;
Plot3( 0.995 * Decycle, "LowerBand" ) ;       
   


Indicator: Decycler Oscillator

// TASC Sep 2015
// Decyclers - John F. Ehlers
// Decycler Oscillator

inputs:
    HPPeriod( 125 ),
    K( 1 ) ;
   
variables:
    alpha1( 0 ),
    alpha2( 0 ),
    HP( 0 ),
    Decycle( 0 ),
    DecycleOsc( 0 ) ;
   

alpha1 = ( Cosine ( 0.707 * 360 / HPPeriod ) +
Sine( 0.707 * 360 / HPPeriod ) - 1 )
/ Cosine( .707 * 360 / HPPeriod ) ;

HP = ( 1 - alpha1 / 2 ) * ( 1 - alpha1 / 2 ) *
( Close - 2 * Close[1] + Close[2] ) + 2 *
( 1 - alpha1 ) * HP[1] - ( 1 - Alpha1 ) *
( 1 - alpha1 ) * HP[2] ;       

Decycle = Close - HP ;


alpha2 = ( Cosine( 0.707 * 360 / ( 0.5 * HPPeriod ) )
+ Sine( 0.707 * 360 / ( 0.5 * HPPeriod ) ) - 1) /
Cosine( 0.707 * 360 / ( 0.5 * HPPeriod ) ) ;

DecycleOsc = ( 1 - alpha2 / 2 ) * ( 1 - alpha2 / 2 ) *
( Decycle - 2 * Decycle[1] + Decycle[2] ) + 2 *
( 1 - alpha2 ) * DecycleOsc[1] - ( 1 - alpha2 ) *
( 1 - alpha2 ) * DecycleOsc[2] ;


Plot1( 100 * K * DecycleOsc / Close, "DecycleOsc" ) ;
Plot2( 0, "ZeroLine" ) ;



Function: DecyclerOscillator

// TASC Sep 2015
// Decyclers - John F. Ehlers
// Decycler Oscillator Function

inputs:
    Price( NumericSeries ),
    HPPeriod( NumericSimple ),
    K( NumericSimple ) ;
   
variables:
    alpha1( 0 ),
    alpha2( 0 ),
    HP( 0 ),
    Decycle( 0 ),
    DecycleOsc( 0 ) ;
   
// High Pass Filter
alpha1 = ( Cosine ( 0.707 * 360 / HPPeriod ) +
Sine( 0.707 * 360 / HPPeriod ) - 1 ) /
Cosine( .707 * 360 / HPPeriod ) ;

HP = ( 1 - alpha1 / 2 ) * ( 1 - alpha1 / 2 ) *
( Price - 2 * Price[1] + Price[2] ) + 2 *
( 1 - alpha1 ) * HP[1] - ( 1 - Alpha1 ) *
( 1 - alpha1 ) * HP[2] ;       

Decycle = Price - HP ;

alpha2 = ( Cosine( 0.707 * 360 / ( 0.5 * HPPeriod ) )
+ Sine( 0.707 * 360 / ( 0.5 * HPPeriod ) ) - 1) /
Cosine( 0.707 * 360 / ( 0.5 * HPPeriod ) ) ;

DecycleOsc = ( 1 - alpha2 / 2 ) * ( 1 - alpha2 / 2 ) *
( Decycle - 2 * Decycle[1] + Decycle[2] ) + 2 *
( 1 - alpha2 ) * DecycleOsc[1] - ( 1 - alpha2 ) *
( 1 - alpha2 ) * DecycleOsc[2] ;

DecyclerOscillator = 100 * K * DecycleOsc / Price ;


Strategy: Decycler Oscillator

// TASC Sep 2015
// Decyclers - John F. Ehlers
// Decycler Oscillator Strategy

inputs:
    Price( Close ),
    Fast_HPPeriod( 100 ),
    Fast_K( 1.2 ),
    Slow_HPPeriod( 125 ),
    Slow_K( 1 ) ;

variables:
    Fast_Val( 0 ),
    Slow_Val( 0 ) ;

Fast_Val =
DecyclerOscillator( Price, Fast_HPPeriod, Fast_K ) ;

Slow_Val =
DecyclerOscillator( Price, Slow_HPPeriod, Slow_K ) ;

if Fast_Val crosses over Slow_Val then
    Buy next bar at Market
else if Slow_Val crosses over Fast_Val then
    SellShort next bar at Market ;
 

pfriedl

New member
Hi all, I'm hoping I can get help with converting a snippet of Easy Language to ThinkScript. This is for plotting potential trend reversals, and I'd like to make sure that the code mirrors the easy language. Here's the easy language code:
Code:
variables:
    PlotDots(true),
    LookBack(4),
    Offset(.25);
if low < low[1] and close >= low + .5 * Range then
begin   
    if CountIf(low < low[1],LookBack + 1) = LookBack + 1
        then plot2(low - Offset * Average(Range,10),"Long+")
        else if PlotDots then plot1(low - Offset * Average(Range,10),"Long");
end;
I can't find very good references for Easy Language - it seems their documentation is spread all over PDFs and random old pages. Any help is appreciated!
 

Slippage

Active member
@pfriedl I'm guessing this 1272 page pdf is the most complete EasyLanguage reference available. https://uploads.tradestation.com/uploads/EasyLanguage-Functions-and-Reserved-Words-Reference.pdf

That code snippet isn't using any reserved words though except CountIf which works how you'd expect based on that code. It's being used to check if a condition is true on every bar for the last x bars. Then the code updates one plot or the other. If you need the look back to be a dynamic length using an input you'd need to use fold to loop. If a static length is fine then the code is simpler.

I think this is equivalent but definitely review/proofread this and test it thoroughly. It should at least get you close to what you need. Note that because of the .5 * range in that code the condition is only true on things that move enough in one candle, like /ES or other high priced tickers or using longer timeframes. Testing it on low price stocks on short timeframes it'll never be true.

Ruby:
input PlotDots = yes;
#input LookBack = 4;
input Offset = .25;

# example code has a Range variable but its
# definition isn't included in the example
def Range = 1;

script lowMeetsCriteria {
  input index = 1;
  input range = 1;
  plot result = low < low[index] and close >= low + .5 * range;
}

def result =
  lowMeetsCriteria(1, Range)
  and lowMeetsCriteria(2, Range)
  and lowMeetsCriteria(3, Range)
  and lowMeetsCriteria(4, Range)
;

def value = low - Offset * Average(Range, 10);

plot p1 = if result != 1 then if PlotDots == 1 then value else Double.NaN else Double.NaN;
p1.SetDefaultColor(Color.WHITE);
p1.SetPaintingStrategy(PaintingStrategy.POINTS);

plot p2 = if result == 1 then value else Double.NaN;
p2.SetDefaultColor(Color.YELLOW);
 
Last edited:

pfriedl

New member
@Slippage OK, I was able to find a little more out here, thanks for the nudge!

Range is a function in TS: http://help.tradestation.com/10_00/eng/tsdevhelp/elword/function/range_function_.htm?Highlight=range
"The Range function subtracts the Low of a bar from the High to determine the range of the bar." so if the low was 100 and the high was 102, then the Range would end up being102-100 = 2.

From the definition of Low() http://help.tradestation.com/10_00/eng/tsdevhelp/elword/word/low_reserved_word_.htm?Highlight=low

Code:
if low < low[1] and close >= low + .5 * Range then begin ... end;

is only comparing the current candle "low" to the last candle "low[1]" and if it's lower and the last candle close is greater than the current low + half the current range, then the conditional would be true and it would continue into the nested if statement.

Once it passes that initial test, we hit the CountIf. and CountIf looks like it actually returns the number of times a statement is true over N candles as opposed to returning true/false if all or none of the conditions were met.

So whether that test fails or not, it's still rendering a plot, but with just a difference in the label (Long vs Long+)?
 

Slippage

Active member
Yeah, you're right. I messed up where that first condition is. For CountIf, look at the entire if condition. It's checking if the count equals all the bars it looked at. Here's an update with fixes but I don't see any cases on my charts where it's true (yellow plot) now. Do you have any example symbol and date/time it should find something?

Ruby:
input PlotDots = yes;
input Offset = .25;

def range = high - low;

def result =
  low < low[1] and close >= low + .5 * range
  and low[1] < low[2]
  and low[2] < low[3]
  and low[3] < low[4]
  and low[4] < low[5]
;

def value = low - Offset * Average(range, 10);

plot p1 = if result != 1 then if PlotDots == 1 then value else Double.NaN else Double.NaN;
p1.SetDefaultColor(Color.WHITE);
p1.SetPaintingStrategy(PaintingStrategy.POINTS);

plot p2 = if result == 1 then value else Double.NaN;
p2.SetDefaultColor(Color.YELLOW);
p2.SetLineWeight(3);
 

Slippage

Active member
Okay, so close >= low + .5 * range is looking for a lower wick at least half the size of the bar. I found some on NFLX 1m chart from Friday. 3 of them. And none of them caused reversals. Two flagged sideways and one blew right through continuing lower. There's one with a reversal near the end of the day on AAL.
 

pfriedl

New member
Yeah I don't really see why you'd need the additional check - if it passes the first test, the second is just a conditional on how to paint the plot. I'd say the CountIf is basically looking for 5 straight bars of lower lows in order to show maybe a stronger potential for reversal? Not sure.
 

Slippage

Active member
CountIf is basically looking for 5 straight bars of lower lows in order to show maybe a stronger potential for reversal? Not sure.
Yes, exactly. Making sure it's been in a down trend to reverse from. It looks like it may work well when the trend isn't stronger than usual. I gave it a name and kept it. I'll probably throw it on some charts and keep an eye on it to see how well it works.
 

BeakedFish

New member
Can anyone help me convert a script from EasyLanguage to ThinkScript? I don't really know how to use EasyLanguage and I can't seem to figure out how to convert it into ThinkScript. Thanks!

Code:
{StoRSI}
inputs: RSILen(13), StoLen(21), MA(3), MA2(5);
 
vars:   PV(0), pvt(0), pvb(0);
vars:   OverBought(80), OverSold(20), Middle (50);
Vars:   Sum(0), Counter(0);
 
pvt = RSI(Close, RSILen) - Lowest(RSI(Close, RSILen), STOLen);
pvb = Highest(RSI(Close, RSILen), STOLen) - Lowest(RSI(Close, RSILen), STOLen);
 
Sum = 0;
For counter = 0 To MA - 1 Begin
    pvt = (RSI(Close, RSILen) - Lowest(RSI(Close, RSILen), STOLen)) of counter bars ago;
    pvb = (Highest(RSI(Close, RSILen), STOLen) - Lowest(RSI(Close, RSILen), STOLen)) of counter bars ago;
 
    PV = iff(pvb > 0, pvt/pvb, 0);
    Sum = Sum + PV;
End;
 
PV = iff(MA > 0, Sum / MA, 0);
 
plot1(PV*100, "StoRSI");
plot2(average(PV,MA2)*100, "StoRSI2");
plot3(OverBought, "OB");
plot4(OverSold, "OS");
Plot5(Middle, "M");
 

rad14733

Well-known member
VIP
@BeakedFish Can you post an image of what the indicator looks like as well as a link to the original so we can determine whether there may already be a Study/Indicator like it here please... If there isn't one exactly the same it might be easier to add to it than perform a complete conversion... Have you scoured these forums for a similar Study/Indicator already...??? We shouldn't simply be expected to do conversions without the requester using due diligence to insure that there isn't a comparable Study/Indicator...
 

Similar threads

Top