desktop:desktop_chart_scripting_overview

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

desktop:desktop_chart_scripting_overview [2022/01/10 20:39] – [Converting Tick Values to Display Values] robdesktop:desktop_chart_scripting_overview [2023/09/21 19:58] (current) – external edit 127.0.0.1
Line 259: Line 259:
 <datatables> <datatables>
 ^ Function ^ Description ^ Example ^ ^ Function ^ Description ^ Example ^
-| PLOT_CENTERLINE  | <code lang | Draws a center line at the specified value.PLOT_CENTERLINE(0);</code>   | {{:desktop:plotother_01_centerline.png|}} | +| PLOT_CENTERLINE  | Draws a center line at the specified value.\\ PLOT_CENTERLINE(0);   | {{:desktop:plotother_01_centerline.png|}} | 
-| PLOT_LIMITLINE  | <code lang | Draws a limit line at the specified value.PLOT_LIMITLINE(0);</code>  | {{:desktop:plotother_02_lmitline.png|}} +| PLOT_LIMITLINE  | Draws a limit line at the specified value.\\ PLOT_LIMITLINE(0); | {{:desktop:plotother_02_lmitline.png|}} 
-| PLOT_RANGEMARKERS  | <code lang | Draws range markers at the specified values.PLOT_RANGEMARKERS(60, -60); </code>  | {{:desktop:plotother_03_rangemarkers.png|}}   |+| PLOT_RANGEMARKERS  | Draws range markers at the specified values.\\ PLOT_RANGEMARKERS(60, -60);  | {{:desktop:plotother_03_rangemarkers.png|}}   |
 </datatables> </datatables>
  
Line 327: Line 327:
 ---- ----
  
-<code lang | Example>+<code lang | Example1>
 smaval = SMA((OPEN + HIGH + CLOSE) / 3, 10); smaval = SMA((OPEN + HIGH + CLOSE) / 3, 10);
 plot_line(smaval, 1, Color.Blue); plot_line(smaval, 1, Color.Blue);
Line 412: Line 412:
  
 To convert a cash value back to ticks use the CASHTICKS function. To convert a cash value back to ticks use the CASHTICKS function.
 +
 +====== The IF Statement ======
 +
 +The IF statement allows you to make decisions on the fly in your scripts. It's syntax is a follows:
 +
 +IF( < test condition >, < true part >, < false part > )
 +
 +The test condition is evaluated (for example: CLOSE > OPEN which would be true when the close price of the bar is greater than the open price of the bar). If true, the true part is returned, otherwise the false part is returned.
 +
 +IF statements are very flexible and can be used to solve a large number of different problems.
 +
 +Here is an example Money Flow Index script:
 +
 +----
 +
 +<code lang | example> 
 +// Make the number of periods configurable.
 +mfperiods = INPUT("MFI Periods", 14, 1, 100);
 +
 +// Net money flow for this period.
 +mf = TYP * V;
 +
 +// Aggregate the net money flow over the user-specified number of periods.
 +posmf = SUM(IF(TYP > TYP[-1], mf, 0), mfperiods);
 +negmf = SUM(IF(TYP < TYP[-1], mf, 0), mfperiods);
 +
 +// Compute the money flow index for this period, taking care not to divide by zero.
 +mfi = IF( negmf = 0, 
 +          IF(posmf = 0, 50, 100),
 +          100 - 100 / (1 + posmf / negmf));
 +
 +// Plot the money flow as a wavecrest centered at 50 with overbought and oversold levels at 80 and 20.
 +PLOT_WAVECREST(mfi, 50, 70, 30, 1, Color.Brown, Color.Brown); 
 +SUMMARY("MFI({?})  {?:F2}", mfperiods, mfi);
 +</code>
 +
 +----
 +
 +The IF statement was used in a number of different places within this script. It's first use is when we want to add up the positive and negative money flows into two distinct variables. IF(TYP > TYP-1, mf, 0) What this is saying, is if the Typical price is greater than the previous Typical price add the net money flow for this bar, otherwise add zero. Vice versa for the negative money flow: IF(TYP < TYP-1, mf, 0), if the Typical price is smaller than the previous Typical price, add the net money flow for this bar.
 +
 +The next uses of the IF statement in this script is even more interesting. We nested an IF statement within another IF statement, which perfectly legal syntax. In this case we want to ensure we don't divide by zero (because that would cause our computation to fail). We also want default values based on whether the neg and/or the pos money flow are equal to zero. The logic in computing the mfi variable could be broken down into a table for easier understanding:
 +
 +----
 +
 +__**Initial Data**__
 +<datatables>
 +^ negmf = 0 ^ posmf = 0 ^ Result ^
 +| False| False   | 100 - 100 / (1 + posmf / negmf))   |
 +| False | True   | 100 - 100 / (1 + posmf / negmf))  |
 +| True  | False   | 100   |
 +| True   | True   | 50   |
 +</datatables>
 +
 +
 +----
 +
 +
 +If statements can be used in other places as well. Look at the following example:
 +
 +----
 +<code lang | Example> 
 +PLOT_HISTOGRAM(VOLUME, 0.72, Color.Blue);
 +SUMMARY("Volume  {0:N0}", VOLUME);
 +</code>
 +
 +----
 + 
 +This produces:
 +
 +{{:desktop:ifstatement_01.png|Image}}
 +
 +However, suppose we want to color the bars a different color if the market closes higher than it opened? Here is one way to accomplish that:
 +
 +----
 +<code lang | example> 
 +PLOT_HISTOGRAM(VOLUME, 0.72, IF(CLOSE > OPEN, Color.Blue, Color.Green));
 +SUMMARY("Volume  {0:N0}", VOLUME);
 +</code>
 +
 +----
 +
 +{{:desktop:ifstatement_02.png|Image}}
 +
 +As you can see, the IF statement is very versatile. Use as needed to make your scripts smarter.
 +
 +====== The NIL Field ======
 +
 +NIL is a field value similar to OPEN, HIGH, LOW, CLOSE, VOLUME, etc. However, NIL is special in that is represents nothing. You can use NIL to short-circuit computations when certain conditions are met, and more importantly, you can use it to suppress plotting when you don't want a certain data point plotted.
 +
 +
 +----
 +
 +<code lang | Consider a script for Pro-Rated volume:> 
 +prvol = IF(BARPERCENT > 0.05, VOLUME / BARPERCENT, VOLUME[-1]);
 +
 +// Plot the pro-rated volume bar.
 +PLOT_HISTOGRAM(IF(INDEX >= COUNT - 1, prvol, NIL), 0.9, COLOR.Yellow);
 +
 +// Plot the real volume.
 +PLOT_HISTOGRAM(VOLUME, 0.7, IF(CLOSE >= OPEN, COLOR("#F08080"), COLOR("#696969")));
 +
 +// Summary.
 +SUMMARY("PRVOL: {?:F0}  VOL: {?} ({?:F0}%)", IF(INDEX >= COUNT - 1, prvol, "-"), VOLUME, 100 * BARPERCENT);
 +</code>
 +
 +----
 +
 +{{:desktop:nil_01.png|Image}}
 +
 +In this script, we pro-rate the volume for the current bar. We accomplish this using the special BARPERCENT field which returns the percentage of time into the current bar we are. We want to plot the pro-rated volume only for the last bar on the chart, and then we want to overlay a plot of the real volume.
 +
 +To ensure the first histogram plots only the last bar, we check the current bar INDEX against the total bar COUNT. If not on the last bar, we pass NIL as the value to plot which basically means "don't plot anything."
 +
 +====== Gotcha 1: Don't Reassign Variables ======
 +
 +Once you assign a value or compuation to a variable name. Do not re-assign a different value to that same variable name. The following example illustrates what not to do:
 +
 +----
 +
 +<code lang | Gotcha example 1> 
 +xval = 10;
 +xval = xval + 1;
 +</code>
 +
 +----
 +
 +Though this sort of syntax works in many conventional programming languages, it will result in a script interpreter error and the result will not be as expected.
 +
 +Remember to think of variables as columns in a spreadsheet. You cannot give a spreadsheet cell more than one formula which is essentially what the above script is attempting to do.
 +
 +====== Gotcha 2: Don't Cause Circular References ======
 +
 +Similar to variable re-assignment, you should watch out for circular references. A circular reference is when two or more variables depend on each other in a circular fashion. For example:
 +
 +----
 +
 +<code lang | Gotcha example 2> 
 +xval = yval;
 +yval = xval + 1;
 +</code>
 +
 +----
 +
 +The script interpreter cannot compute xval until it computes yval. It also cannot compute yval until it computes xval. A naive interpreter might get stuck in an endless loop trying to solve these equations, however the script interpreter has a mechanism to detect these situations and report them as errors.
 +
 +====== Recursion ======
 +
 +There is a special case where you can use circular-like syntax called recursion. Here is an example:
 +
 +----
 +
 +<code lang | Example>
 +xval = IF(INDEX = 0, 0, yval[-1]);
 +yval = xval + 1;
 +</code>
 +
 +or
 +
 +<code lang | Example2>
 +yval = IF(INDEX = 0, 0, yval[-1] + 1);
 +</code>
 +
 +----
 +
 +In this case, because you using the offset mechanism to refer to a previously calculated value, no circular reference error is generated. However, you must be sure to check the stop condition and assign it a value. In this case our stop condition is the first bar. On the first bar, the previous value of yval would evaulate to NIL and that would short-circuit all following computations to NIL. We used the IF statement to initialize yval on the first bar.
 +
 +Recursion is considered an extremely advanced topic. It is rarely needed for most indicator calculations. However there are some calculations which are impossible without it (Parabolic SAR is one example). If find find yourself using recursion to solve a computation problem, please feel free to contact support for assistance, further documentation and possibly more examples.
  
  • desktop/desktop_chart_scripting_overview.1641847186.txt.gz
  • Last modified: 2023/09/21 19:55
  • (external edit)