|
| 1 | +--- |
| 2 | +layout: default |
| 3 | +title: Syntax Guide |
| 4 | +nav_order: 3 |
| 5 | +--- |
| 6 | + |
| 7 | +# PineTS Syntax Guide |
| 8 | + |
| 9 | +This guide explains how to write PineTS code that is equivalent to Pine Script. PineTS is designed to be written in JavaScript/TypeScript but behaves like Pine Script's runtime execution model. |
| 10 | + |
| 11 | +## Variable Declarations |
| 12 | + |
| 13 | +PineTS distinguishes between `let` and `var` declarations to mimic Pine Script's behavior. This is a critical difference from standard JavaScript. |
| 14 | + |
| 15 | +### `let` vs `var` |
| 16 | + |
| 17 | +| Feature | Pine Script | PineTS (JS/TS) | Behavior | |
| 18 | +| :-------------------- | :------------------ | :-------------- | :----------------------------------------------------------------------------------- | |
| 19 | +| **Re-initialization** | `float x = close` | `let x = close` | Variable is re-initialized/calculated **on every bar**. | |
| 20 | +| **State Persistence** | `var float x = 0.0` | `var x = 0.0` | Variable is initialized **only once** (first bar) and retains its value across bars. | |
| 21 | + |
| 22 | +**⚠️ Important for JS Developers:** In PineTS, `var` does **not** behave like standard JavaScript `var`. It adopts Pine Script's `var` semantics (persistent state). If you need standard JS function-scoped variables that reset every time, use `let`. |
| 23 | + |
| 24 | +#### Example: State Persistence |
| 25 | + |
| 26 | +**Pine Script:** |
| 27 | + |
| 28 | +```pinescript |
| 29 | +// 'sum' retains its value across bars |
| 30 | +var float sum = 0.0 |
| 31 | +sum := sum + close |
| 32 | +``` |
| 33 | + |
| 34 | +**PineTS:** |
| 35 | + |
| 36 | +```javascript |
| 37 | +// 'sum' retains its value across bars |
| 38 | +var sum = 0.0; |
| 39 | +sum = sum + close; |
| 40 | +``` |
| 41 | + |
| 42 | +## Loops |
| 43 | + |
| 44 | +PineTS supports standard JavaScript loops, which map to Pine Script's loops. |
| 45 | + |
| 46 | +| Feature | Pine Script | PineTS (JS/TS) | |
| 47 | +| :------------- | :---------------- | :------------------------------ | |
| 48 | +| **For Loop** | `for i = 0 to 10` | `for (let i = 0; i <= 10; i++)` | |
| 49 | +| **While Loop** | `while i < 10` | `while (i < 10)` | |
| 50 | + |
| 51 | +#### Example: For Loop |
| 52 | + |
| 53 | +**Pine Script:** |
| 54 | + |
| 55 | +```pinescript |
| 56 | +float sum = 0.0 |
| 57 | +for i = 0 to 9 |
| 58 | + sum := sum + close[i] |
| 59 | +``` |
| 60 | + |
| 61 | +**PineTS:** |
| 62 | + |
| 63 | +```javascript |
| 64 | +let sum = 0.0; |
| 65 | +for (let i = 0; i < 10; i++) { |
| 66 | + sum += close[i]; |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +## Control Structures |
| 71 | + |
| 72 | +### Switch Statement |
| 73 | + |
| 74 | +PineTS supports the JavaScript `switch` statement, which is equivalent to Pine Script's `switch`. |
| 75 | + |
| 76 | +**Pine Script:** |
| 77 | + |
| 78 | +```pinescript |
| 79 | +switch type |
| 80 | + "ema" => ta.ema(close, len) |
| 81 | + "sma" => ta.sma(close, len) |
| 82 | + => ta.rma(close, len) |
| 83 | +``` |
| 84 | + |
| 85 | +**PineTS:** |
| 86 | + |
| 87 | +```javascript |
| 88 | +switch (type) { |
| 89 | + case 'ema': |
| 90 | + return ta.ema(close, len); |
| 91 | + case 'sma': |
| 92 | + return ta.sma(close, len); |
| 93 | + default: |
| 94 | + return ta.rma(close, len); |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +## Functions |
| 99 | + |
| 100 | +User-defined functions in PineTS are written as standard JavaScript functions. |
| 101 | + |
| 102 | +**Pine Script:** |
| 103 | + |
| 104 | +```pinescript |
| 105 | +f_ma(source, length) => |
| 106 | + ta.sma(source, length) |
| 107 | +``` |
| 108 | + |
| 109 | +**PineTS:** |
| 110 | + |
| 111 | +```javascript |
| 112 | +function f_ma(source, length) { |
| 113 | + return ta.sma(source, length); |
| 114 | +} |
| 115 | +``` |
| 116 | + |
| 117 | +## Tuples and Multiple Return Values |
| 118 | + |
| 119 | +Pine Script allows functions to return multiple values (tuples). PineTS handles this using array destructuring. |
| 120 | + |
| 121 | +**Pine Script:** |
| 122 | + |
| 123 | +```pinescript |
| 124 | +[macdLine, signalLine, histLine] = ta.macd(close, 12, 26, 9) |
| 125 | +``` |
| 126 | + |
| 127 | +**PineTS:** |
| 128 | + |
| 129 | +```javascript |
| 130 | +const [macdLine, signalLine, histLine] = ta.macd(close, 12, 26, 9); |
| 131 | +``` |
| 132 | + |
| 133 | +## Series and History Access |
| 134 | + |
| 135 | +Accessing historical values is done using the `[]` operator in Pine Script. In PineTS, array access syntax is supported and transpiled to safe series access. |
| 136 | + |
| 137 | +| Feature | Pine Script | PineTS (JS/TS) | Notes | |
| 138 | +| :----------------- | :---------- | :------------- | :---------------------------------- | |
| 139 | +| **Current Value** | `close` | `close` | References the current bar's value. | |
| 140 | +| **Previous Value** | `close[1]` | `close[1]` | References the value 1 bar ago. | |
| 141 | +| **History Access** | `close[10]` | `close[10]` | References the value 10 bars ago. | |
| 142 | + |
| 143 | +**PineTS:** |
| 144 | + |
| 145 | +```javascript |
| 146 | +// Calculate momentum |
| 147 | +let mom = close - close[10]; |
| 148 | +``` |
| 149 | + |
| 150 | +## Conditional Logic |
| 151 | + |
| 152 | +PineTS supports standard JavaScript control flow, which maps to Pine Script's execution model. |
| 153 | + |
| 154 | +| Feature | Pine Script | PineTS (JS/TS) | Notes | |
| 155 | +| :--------------- | :---------------------------------------------- | :--------------------------------------------------------- | :------------------ | |
| 156 | +| **If Statement** | `if condition`<br> `...` | `if (condition) {`<br> `...`<br>`}` | Standard JS syntax. | |
| 157 | +| **Ternary** | `cond ? val1 : val2` | `cond ? val1 : val2` | Standard JS syntax. | |
| 158 | + |
| 159 | +#### Example: Trend Direction |
| 160 | + |
| 161 | +**Pine Script:** |
| 162 | + |
| 163 | +```pinescript |
| 164 | +if close > open |
| 165 | + direction := 1 |
| 166 | +else |
| 167 | + direction := -1 |
| 168 | +``` |
| 169 | + |
| 170 | +**PineTS:** |
| 171 | + |
| 172 | +```javascript |
| 173 | +if (close > open) { |
| 174 | + direction = 1; |
| 175 | +} else { |
| 176 | + direction = -1; |
| 177 | +} |
| 178 | +``` |
| 179 | + |
| 180 | +## Built-in Variables |
| 181 | + |
| 182 | +PineTS exposes Pine Script's built-in variables through the `context` object, but usually, you destructure them for easier access. |
| 183 | + |
| 184 | +| Variable | Pine Script | PineTS (JS/TS) | |
| 185 | +| :-------------- | :---------- | :-------------------------------- | |
| 186 | +| **Close Price** | `close` | `close` (from `context.data`) | |
| 187 | +| **Open Price** | `open` | `open` (from `context.data`) | |
| 188 | +| **High Price** | `high` | `high` (from `context.data`) | |
| 189 | +| **Low Price** | `low` | `low` (from `context.data`) | |
| 190 | +| **Volume** | `volume` | `volume` (from `context.data`) | |
| 191 | +| **Bar Index** | `bar_index` | `bar_index` (from `context.pine`) | |
| 192 | + |
| 193 | +**PineTS Setup:** |
| 194 | + |
| 195 | +```javascript |
| 196 | +const { close, high, low } = context.data; |
| 197 | +const { bar_index } = context.pine; |
| 198 | +``` |
| 199 | + |
| 200 | +## Functions and Namespaces |
| 201 | + |
| 202 | +PineTS organizes built-in functions into namespaces similar to Pine Script v5. |
| 203 | + |
| 204 | +| Namespace | Pine Script | PineTS (JS/TS) | Example | |
| 205 | +| :--------------------- | :---------- | :------------- | :---------------------- | |
| 206 | +| **Technical Analysis** | `ta.*` | `ta.*` | `ta.sma(close, 14)` | |
| 207 | +| **Math** | `math.*` | `math.*` | `math.max(high, low)` | |
| 208 | +| **Request** | `request.*` | `request.*` | `request.security(...)` | |
| 209 | + |
| 210 | +**PineTS Setup:** |
| 211 | + |
| 212 | +```javascript |
| 213 | +const { ta, math } = context.pine; |
| 214 | +// Usage |
| 215 | +const sma = ta.sma(close, 14); |
| 216 | +``` |
| 217 | + |
| 218 | +## Full Example: Parabolic SAR |
| 219 | + |
| 220 | +This example demonstrates `var` for state, `if/else` logic, and history access. |
| 221 | + |
| 222 | +**Pine Script:** |
| 223 | + |
| 224 | +```pinescript |
| 225 | +pine_sar(start, inc, max) => |
| 226 | + var float result = na |
| 227 | + var float maxMin = na |
| 228 | + var float acceleration = na |
| 229 | + var bool isBelow = false |
| 230 | + bool isFirstTrendBar = false |
| 231 | +
|
| 232 | + if bar_index == 1 |
| 233 | + if close > close[1] |
| 234 | + isBelow := true |
| 235 | + maxMin := high |
| 236 | + result := low[1] |
| 237 | + else |
| 238 | + isBelow := false |
| 239 | + maxMin := low |
| 240 | + result := high[1] |
| 241 | + isFirstTrendBar := true |
| 242 | + acceleration := start |
| 243 | +
|
| 244 | + // ... logic continues ... |
| 245 | + result |
| 246 | +``` |
| 247 | + |
| 248 | +**PineTS:** |
| 249 | + |
| 250 | +```javascript |
| 251 | +function pine_sar(start, inc, max) { |
| 252 | + // Use 'var' for state variables (persistent) |
| 253 | + var result = na; |
| 254 | + var maxMin = na; |
| 255 | + var acceleration = na; |
| 256 | + var isBelow = false; |
| 257 | + |
| 258 | + // Use 'let' for temporary variables (reset every bar) |
| 259 | + let isFirstTrendBar = false; |
| 260 | + |
| 261 | + if (bar_index == 1) { |
| 262 | + if (close > close[1]) { |
| 263 | + isBelow = true; |
| 264 | + maxMin = high; |
| 265 | + result = low[1]; |
| 266 | + } else { |
| 267 | + isBelow = false; |
| 268 | + maxMin = low; |
| 269 | + result = high[1]; |
| 270 | + } |
| 271 | + isFirstTrendBar = true; |
| 272 | + acceleration = start; |
| 273 | + } |
| 274 | + |
| 275 | + // ... logic continues ... |
| 276 | + |
| 277 | + return result; |
| 278 | +} |
| 279 | +``` |
0 commit comments