@kuandotdev/indicator 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -7
- package/package.json +4 -1
- package/project/.cursor/rules/agent-docs.mdc +16 -0
- package/project/.cursor/rules/api-credential-storage.mdc +16 -0
- package/project/.cursor/rules/pinescript-v6.mdc +16 -0
- package/project/.cursor/rules/stock-model-forecast.mdc +16 -0
- package/project/.cursor/rules/system-prompt-injection.mdc +16 -0
- package/project/.cursor/rules/system-prompt-updater.mdc +16 -0
- package/project/.cursor/rules/tradingview-stock-data.mdc +16 -0
- package/project/.env.example +44 -0
- package/project/.npm-packaged-project +1 -0
- package/project/.pi/APPEND_SYSTEM.md +338 -0
- package/project/.pi/settings.json +8 -0
- package/project/AGENTS.md +538 -0
- package/project/CLAUDE.md +538 -0
- package/project/GEMINI.md +538 -0
- package/project/Makefile +488 -0
- package/project/README.md +419 -0
- package/project/conda-env-active.sh +98 -0
- package/project/conda-env-deactive.sh +42 -0
- package/project/docs/agent-install.md +446 -0
- package/project/docs/agent-skill-directory.md +222 -0
- package/project/docs/integration.html +271 -0
- package/project/packages/indicator/README.md +39 -0
- package/project/packages/indicator/package.json +40 -0
- package/project/packages/indicator/scripts/build-project-snapshot.js +57 -0
- package/project/packages/indicator/src/cli.js +368 -0
- package/project/packages/tradingview-stock-data-skill/README.md +112 -0
- package/project/packages/tradingview-stock-data-skill/extensions/stock-prompt-injector.ts +121 -0
- package/project/packages/tradingview-stock-data-skill/package.json +35 -0
- package/project/packages/tradingview-stock-data-skill/scripts/postinstall.sh +73 -0
- package/project/packages/tradingview-stock-data-skill/skills/tradingview-stock-data/SKILL.md +241 -0
- package/project/pyproject.toml +68 -0
- package/project/screenshots/.gitkeep +0 -0
- package/project/scripts/indicators/example_rsi_bands.pine +27 -0
- package/project/scripts/indicators/tsla_levels.pine +57 -0
- package/project/skills/agent-docs/SKILL.md +56 -0
- package/project/skills/api-credential-storage/SKILL.md +83 -0
- package/project/skills/api-credential-storage/scripts/upsert_env.py +151 -0
- package/project/skills/pinescript-v6/SKILL.md +129 -0
- package/project/skills/pinescript-v6/reference/built-ins.md +219 -0
- package/project/skills/pinescript-v6/reference/templates/alert-webhook.pine +76 -0
- package/project/skills/pinescript-v6/reference/templates/indicator.pine +48 -0
- package/project/skills/pinescript-v6/reference/templates/strategy.pine +50 -0
- package/project/skills/pinescript-v6/reference/v5-to-v6-migration.md +102 -0
- package/project/skills/pinescript-v6/reference/v6-language.md +202 -0
- package/project/skills/stock-model-forecast/SKILL.md +192 -0
- package/project/skills/system-prompt-injection/CUSTOM_SYSTEM_PROMPT.md +333 -0
- package/project/skills/system-prompt-injection/DEFAULT_SYSTEM_PROMPT.md +327 -0
- package/project/skills/system-prompt-injection/SKILL.md +90 -0
- package/project/skills/system-prompt-injection/SYSTEM_PROMPT.md +23 -0
- package/project/skills/system-prompt-updater/SKILL.md +82 -0
- package/project/skills/system-prompt-updater/scripts/system_prompt_update.sh +106 -0
- package/project/skills/tradingview-stock-data/SKILL.md +272 -0
- package/project/src/tv_indicator/__init__.py +0 -0
- package/project/src/tv_indicator/browser/__init__.py +0 -0
- package/project/src/tv_indicator/browser/automation.py +541 -0
- package/project/src/tv_indicator/browser/selectors.py +70 -0
- package/project/src/tv_indicator/cli/__init__.py +0 -0
- package/project/src/tv_indicator/cli/browser_cmds.py +92 -0
- package/project/src/tv_indicator/cli/data_cmds.py +178 -0
- package/project/src/tv_indicator/cli/main.py +56 -0
- package/project/src/tv_indicator/cli/model_cmds.py +255 -0
- package/project/src/tv_indicator/cli/pine_cmds.py +140 -0
- package/project/src/tv_indicator/config.py +98 -0
- package/project/src/tv_indicator/data/__init__.py +0 -0
- package/project/src/tv_indicator/data/client.py +187 -0
- package/project/src/tv_indicator/data/screener.py +268 -0
- package/project/src/tv_indicator/mcp/__init__.py +0 -0
- package/project/src/tv_indicator/mcp/agent_server.py +398 -0
- package/project/src/tv_indicator/mcp/browser_server.py +133 -0
- package/project/src/tv_indicator/mcp/data_server.py +239 -0
- package/project/src/tv_indicator/model/__init__.py +19 -0
- package/project/src/tv_indicator/model/forecast.py +693 -0
- package/project/tools/import_agent_tools.sh +503 -0
- package/project/tools/install_skills.sh +673 -0
- package/project/tools/interactive_install.sh +917 -0
- package/project/tools/progress.sh +114 -0
- package/project/tools/uninstall_agent_tools.sh +373 -0
- package/src/cli.js +22 -25
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pinescript-v6
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill whenever authoring, editing, reviewing, or migrating PineScript code,
|
|
5
|
+
and whenever a market-analysis workflow needs PineScript-compatible indicator semantics
|
|
6
|
+
such as default MACD analysis or user-requested RSI/SMA/EMA/Bollinger/ATR/VWAP logic.
|
|
7
|
+
Code triggers include .pine files, `//@version=`, `indicator(...)`, `strategy(...)`,
|
|
8
|
+
`library(...)`, `request.security`, `ta.*`, `strategy.*`, `array.*`, `matrix.*`,
|
|
9
|
+
`map.*`, etc. The skill encodes Pine Script v6 syntax, common patterns, and v5→v6
|
|
10
|
+
migration rules so generated code compiles in TradingView's Pine Editor.
|
|
11
|
+
Trigger phrases: "write a pine indicator", "pinescript strategy", "convert v5 to v6",
|
|
12
|
+
"fix this pine script", "create alert with webhook", "tradingview indicator".
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# PineScript v6 authoring skill
|
|
16
|
+
|
|
17
|
+
## Market-analysis indicator workflow
|
|
18
|
+
|
|
19
|
+
For stock/ETF/crypto/forex/futures/index analysis requests, use this skill for PineScript-compatible indicator semantics even when no `.pine` file is being edited.
|
|
20
|
+
|
|
21
|
+
Default behavior:
|
|
22
|
+
|
|
23
|
+
1. Pull recent OHLCV through `tradingview-stock-data`.
|
|
24
|
+
2. Compute/interpret MACD by default using Pine-compatible `ta.macd` semantics: EMA fast 12, EMA slow 26, signal EMA 9, plus histogram.
|
|
25
|
+
3. Classify the signal as bullish, bearish, improving, weakening, or neutral from MACD line vs signal line, histogram direction, zero-line position, and recent crossovers.
|
|
26
|
+
4. If the user requests another indicator, use that indicator instead or in addition: RSI, SMA/EMA, Bollinger Bands, ATR, VWAP, or custom PineScript logic.
|
|
27
|
+
5. Feed the indicator result into the agent-evaluated `Rating: {Buy | Sell | hold}` plus Buy/Sell score. Do not treat TradingView's aggregate rating as the report rating.
|
|
28
|
+
|
|
29
|
+
Only create or edit a Pine file when the user asks for code, a reusable indicator/strategy, or a TradingView chart script. If a `.pine` file is written or modified, run the validation checklist below before claiming it is ready.
|
|
30
|
+
|
|
31
|
+
## ⚠️ Always check version first
|
|
32
|
+
|
|
33
|
+
Every PineScript file MUST start with a version directive:
|
|
34
|
+
|
|
35
|
+
```pinescript
|
|
36
|
+
//@version=6
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
If the user provides code without `//@version=`, ask which version OR default to **v6**.
|
|
40
|
+
**Never silently mix v4/v5/v6 syntax** — it will not compile.
|
|
41
|
+
|
|
42
|
+
## Required reading before writing Pine code
|
|
43
|
+
|
|
44
|
+
Load these in order based on the task:
|
|
45
|
+
|
|
46
|
+
| Task | Files to read |
|
|
47
|
+
|---|---|
|
|
48
|
+
| New indicator from scratch | `reference/v6-language.md`, `reference/built-ins.md`, `reference/templates/indicator.pine` |
|
|
49
|
+
| New strategy from scratch | `reference/v6-language.md`, `reference/built-ins.md`, `reference/templates/strategy.pine` |
|
|
50
|
+
| Strategy with webhook alerts (for automation) | `reference/templates/alert-webhook.pine` |
|
|
51
|
+
| Convert / migrate existing code | `reference/v5-to-v6-migration.md` first, then `reference/built-ins.md` |
|
|
52
|
+
| Fix compile errors | `reference/v5-to-v6-migration.md` (most errors are v5-isms) |
|
|
53
|
+
|
|
54
|
+
Paths are relative to this SKILL.md's directory.
|
|
55
|
+
|
|
56
|
+
## Core authoring rules (apply every time)
|
|
57
|
+
|
|
58
|
+
1. **One declaration statement per script**: exactly one `indicator()`, `strategy()`, or `library()` call near the top, after `//@version=6`.
|
|
59
|
+
2. **Use namespaces explicitly**:
|
|
60
|
+
- `ta.sma()` not `sma()` (the un-namespaced form is v4)
|
|
61
|
+
- `math.abs()` not `abs()`
|
|
62
|
+
- `array.new<float>()` not `array.new_float()` (v6 prefers typed generics)
|
|
63
|
+
- `str.tostring()` not `tostring()`
|
|
64
|
+
3. **Series vs simple types**: most TA functions need series; constants are `simple`/`const`. If you see `Cannot call X with arguments...` errors, this is usually the cause.
|
|
65
|
+
4. **`request.security` lookahead**: always pass `barmerge.lookahead_off` unless intentionally peeking. Lookahead-on without `[1]` offset = repainting.
|
|
66
|
+
5. **Strategy realism**: in `strategy(...)` declarations include `process_orders_on_close=true` and `calc_on_every_tick=false` for realistic backtests unless the user asks otherwise.
|
|
67
|
+
6. **Alert messages for webhook automation**: use `alert(message, alert.freq_once_per_bar_close)` with a JSON-shaped string. See `reference/templates/alert-webhook.pine`.
|
|
68
|
+
7. **No `var` abuse**: `var` initializes once. Use it for state that persists across bars; don't use it for values that should recompute.
|
|
69
|
+
8. **Plot return values**: indicator() must produce at least one `plot()`, `plotshape()`, `plotchar()`, `bgcolor()`, or `hline()` to be valid.
|
|
70
|
+
9. **Keep the declaration on one line**: TV's parser does NOT reliably accept the multi-line
|
|
71
|
+
`indicator(\n title = "...",\n ... \n )` style — it produces
|
|
72
|
+
"Syntax error at input ..." errors. Always write the `indicator(...)`, `strategy(...)`,
|
|
73
|
+
or `library(...)` call on a single line, even if long. (Local lint won't catch this;
|
|
74
|
+
only TV's compiler will.)
|
|
75
|
+
|
|
76
|
+
## Quick reference: things that changed from v5 → v6
|
|
77
|
+
|
|
78
|
+
| v5 | v6 |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `array.new_float(0)` | `array.new<float>(0)` |
|
|
81
|
+
| `matrix.new<float>(rows, cols, 0.0)` | unchanged ✓ |
|
|
82
|
+
| `if barstate.islast` | unchanged ✓ |
|
|
83
|
+
| Type declarations optional | Stronger inference; explicit types still allowed |
|
|
84
|
+
| `request.security(syminfo.tickerid, "D", close)` | unchanged ✓ but prefer keyword args |
|
|
85
|
+
| `input(...)` | `input.int / input.float / input.bool / input.source` (already true in v5) |
|
|
86
|
+
| Maximum 500 bars `lookback` default | v6 raised some limits — check `reference/v6-language.md` |
|
|
87
|
+
|
|
88
|
+
See `reference/v5-to-v6-migration.md` for the full delta.
|
|
89
|
+
|
|
90
|
+
## Validation checklist before declaring "done"
|
|
91
|
+
|
|
92
|
+
When the user asks you to write/edit Pine code, before responding:
|
|
93
|
+
|
|
94
|
+
- [ ] First line is `//@version=6`
|
|
95
|
+
- [ ] Exactly one `indicator()` / `strategy()` / `library()` call
|
|
96
|
+
- [ ] All built-ins use correct namespace (`ta.`, `math.`, `str.`, `array.`, `request.`, `strategy.`, `input.`)
|
|
97
|
+
- [ ] Every `input.*()` call has a `title=` and a sensible `defval`
|
|
98
|
+
- [ ] `request.security` calls specify `lookahead` explicitly
|
|
99
|
+
- [ ] For strategies: at least one `strategy.entry` / `strategy.close` / `strategy.exit`
|
|
100
|
+
- [ ] For indicators: at least one visible output (`plot`, `plotshape`, `bgcolor`, `hline`)
|
|
101
|
+
- [ ] If the script generates alerts for the user's webhook pipeline (`tv_browser` MCP / live trading), the `alert()` payload is a JSON string that downstream code can parse
|
|
102
|
+
- [ ] No tabs (Pine Editor uses spaces); 4-space indent
|
|
103
|
+
|
|
104
|
+
## Project conventions
|
|
105
|
+
|
|
106
|
+
- Indicators live in `scripts/indicators/*.pine`
|
|
107
|
+
- Strategies live in `scripts/strategies/*.pine`
|
|
108
|
+
- File names use `snake_case.pine`
|
|
109
|
+
- Each file starts with a header comment block:
|
|
110
|
+
```
|
|
111
|
+
// ─────────────────────────────────────────────────────────────
|
|
112
|
+
// Title: <Display name>
|
|
113
|
+
// Author: <user>
|
|
114
|
+
// Description: <one paragraph>
|
|
115
|
+
// Version: v6, <date>
|
|
116
|
+
// ─────────────────────────────────────────────────────────────
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Pushing to TradingView
|
|
120
|
+
|
|
121
|
+
After writing a `.pine` file, the user can push it to their TradingView Premium account via:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
training-view browser push scripts/indicators/<file>.pine --apply NASDAQ:AAPL --screenshot
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This logs in via session cookie, pastes into the Pine Editor, saves, applies to a chart,
|
|
128
|
+
and screenshots. The screenshot ends up in `screenshots/` — read it back to visually
|
|
129
|
+
verify the indicator looks correct before iterating.
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# PineScript v6 — built-in namespaces cheat sheet
|
|
2
|
+
|
|
3
|
+
## `ta.*` — technical analysis
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
ta.sma(src, len) // Simple MA
|
|
7
|
+
ta.ema(src, len) // Exponential MA
|
|
8
|
+
ta.wma(src, len) // Weighted MA
|
|
9
|
+
ta.rma(src, len) // Wilder's smoothing (used by RSI/ATR)
|
|
10
|
+
ta.vwma(src, len) // Volume-weighted MA
|
|
11
|
+
ta.hma(src, len) // Hull MA
|
|
12
|
+
|
|
13
|
+
ta.rsi(src, len) // RSI
|
|
14
|
+
ta.macd(src, fast, slow, sig) // returns [macd, signal, hist]
|
|
15
|
+
ta.bb(src, len, mult) // returns [basis, upper, lower]
|
|
16
|
+
ta.atr(len) // Average True Range (uses high/low/close internally)
|
|
17
|
+
ta.tr(handle_na = true) // True Range
|
|
18
|
+
ta.stoch(src, hi, lo, len) // Stochastic
|
|
19
|
+
ta.cci(src, len)
|
|
20
|
+
ta.mom(src, len)
|
|
21
|
+
ta.roc(src, len)
|
|
22
|
+
|
|
23
|
+
ta.highest(src, len) // Rolling max
|
|
24
|
+
ta.lowest(src, len) // Rolling min
|
|
25
|
+
ta.highestbars(src, len) // Bars-ago index of highest
|
|
26
|
+
ta.lowestbars(src, len)
|
|
27
|
+
|
|
28
|
+
ta.change(src, len = 1) // src - src[len]
|
|
29
|
+
ta.cum(src) // Cumulative sum
|
|
30
|
+
ta.valuewhen(cond, src, occ) // src value at the Nth occurrence of cond
|
|
31
|
+
|
|
32
|
+
ta.crossover(a, b) // bool: a crossed above b this bar
|
|
33
|
+
ta.crossunder(a, b)
|
|
34
|
+
ta.cross(a, b) // either direction
|
|
35
|
+
|
|
36
|
+
ta.pivothigh(src, left, right)
|
|
37
|
+
ta.pivotlow(src, left, right)
|
|
38
|
+
ta.barssince(cond) // bars since cond was true; na if never
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## `math.*`
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
math.abs(x) math.sign(x)
|
|
45
|
+
math.min(a, b) math.max(a, b)
|
|
46
|
+
math.round(x, precision = 0)
|
|
47
|
+
math.floor(x) math.ceil(x)
|
|
48
|
+
math.pow(b, e) math.sqrt(x)
|
|
49
|
+
math.log(x) math.log10(x) math.exp(x)
|
|
50
|
+
math.sin(x) math.cos(x) math.tan(x)
|
|
51
|
+
math.atan(x) math.atan2(y, x)
|
|
52
|
+
math.random(min, max, seed)
|
|
53
|
+
math.sum(src, len)
|
|
54
|
+
math.avg(...) // up to 10 args
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## `str.*`
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
str.tostring(value, format = "#.##")
|
|
61
|
+
str.tonumber(s)
|
|
62
|
+
str.format("Price: {0,number,#.##}", close)
|
|
63
|
+
str.length(s)
|
|
64
|
+
str.contains(s, sub)
|
|
65
|
+
str.startswith(s, sub) str.endswith(s, sub)
|
|
66
|
+
str.replace(s, from, to, occurrence = 0)
|
|
67
|
+
str.replace_all(s, from, to)
|
|
68
|
+
str.split(s, sep) // returns array<string>
|
|
69
|
+
str.upper(s) str.lower(s)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## `array.*`
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
array.new<float>(size = 0, init_value = na)
|
|
76
|
+
array.from(v1, v2, ...) // literal
|
|
77
|
+
array.size(arr)
|
|
78
|
+
array.get(arr, i) array.set(arr, i, v)
|
|
79
|
+
array.push(arr, v) array.pop(arr)
|
|
80
|
+
array.unshift(arr, v) array.shift(arr)
|
|
81
|
+
array.insert(arr, i, v) array.remove(arr, i)
|
|
82
|
+
array.clear(arr)
|
|
83
|
+
array.includes(arr, v) array.indexof(arr, v)
|
|
84
|
+
array.slice(arr, from, to)
|
|
85
|
+
array.sort(arr, order = order.ascending)
|
|
86
|
+
array.reverse(arr)
|
|
87
|
+
array.sum(arr) array.avg(arr) array.min(arr) array.max(arr)
|
|
88
|
+
array.stdev(arr) array.variance(arr) array.median(arr)
|
|
89
|
+
array.join(arr, sep = ",")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## `map.*`
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
map.new<keyType, valueType>()
|
|
96
|
+
map.put(m, k, v) map.get(m, k)
|
|
97
|
+
map.contains(m, k) map.remove(m, k)
|
|
98
|
+
map.keys(m) map.values(m)
|
|
99
|
+
map.size(m) map.clear(m)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## `request.*`
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
request.security(symbol, timeframe, expression,
|
|
106
|
+
gaps = barmerge.gaps_off,
|
|
107
|
+
lookahead = barmerge.lookahead_off,
|
|
108
|
+
ignore_invalid_symbol = false,
|
|
109
|
+
currency = syminfo.currency)
|
|
110
|
+
|
|
111
|
+
request.security_lower_tf(symbol, timeframe, expression)
|
|
112
|
+
// get array of intrabar values
|
|
113
|
+
|
|
114
|
+
request.financial(symbol, financial_id, period)
|
|
115
|
+
// e.g. "TOTAL_REVENUE", period = "FY"|"FQ"|"TTM"
|
|
116
|
+
|
|
117
|
+
request.dividends(symbol, field, gaps, lookahead)
|
|
118
|
+
request.earnings(symbol, field, gaps, lookahead)
|
|
119
|
+
request.splits(symbol, field, gaps, lookahead)
|
|
120
|
+
request.economic(country_code, field)
|
|
121
|
+
request.quandl(...) // legacy
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## `strategy.*`
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
strategy.entry(id, direction, qty = na, limit = na, stop = na,
|
|
128
|
+
oca_name, oca_type, comment, alert_message)
|
|
129
|
+
strategy.order(id, direction, qty, limit, stop, oca_name, oca_type, comment, alert_message)
|
|
130
|
+
strategy.exit(id, from_entry, qty, qty_percent, profit, limit, loss, stop,
|
|
131
|
+
trail_price, trail_points, trail_offset,
|
|
132
|
+
oca_name, comment, alert_message)
|
|
133
|
+
strategy.close(id, comment, qty, qty_percent, alert_message)
|
|
134
|
+
strategy.close_all(comment, alert_message)
|
|
135
|
+
strategy.cancel(id) strategy.cancel_all()
|
|
136
|
+
|
|
137
|
+
// Direction constants
|
|
138
|
+
strategy.long strategy.short
|
|
139
|
+
|
|
140
|
+
// State
|
|
141
|
+
strategy.position_size // signed: + long, - short, 0 flat
|
|
142
|
+
strategy.position_avg_price
|
|
143
|
+
strategy.opentrades // count
|
|
144
|
+
strategy.openprofit
|
|
145
|
+
strategy.netprofit
|
|
146
|
+
strategy.equity
|
|
147
|
+
strategy.initial_capital
|
|
148
|
+
|
|
149
|
+
// Risk management (declarative)
|
|
150
|
+
strategy.risk.allow_entry_in(strategy.direction.long)
|
|
151
|
+
strategy.risk.max_position_size(10)
|
|
152
|
+
strategy.risk.max_drawdown(20, strategy.percent_of_equity)
|
|
153
|
+
strategy.risk.max_intraday_loss(5, strategy.percent_of_equity)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## `input.*`
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
input.int(defval, title, minval, maxval, step, options, tooltip, inline, group)
|
|
160
|
+
input.float(defval, title, minval, maxval, step, options, tooltip, inline, group)
|
|
161
|
+
input.bool(defval, title, ...)
|
|
162
|
+
input.string(defval, title, options = [...], ...)
|
|
163
|
+
input.color(defval, title, ...)
|
|
164
|
+
input.source(defval, title, ...) // returns series: close, hl2, hlc3, etc.
|
|
165
|
+
input.symbol(defval, title, ...) // returns string ticker
|
|
166
|
+
input.timeframe(defval, title, options, ...)
|
|
167
|
+
input.session(defval, title, ...) // e.g. "0930-1600"
|
|
168
|
+
input.time(defval, title, ...)
|
|
169
|
+
input.price(defval, title, ...)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## `color.*`
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
color.new(base, transp) // transp 0 (opaque) - 100 (invisible)
|
|
176
|
+
color.rgb(r, g, b, transp = 0)
|
|
177
|
+
color.from_gradient(value, bottom_value, top_value, bottom_color, top_color)
|
|
178
|
+
color.red color.green color.blue color.yellow color.orange color.purple
|
|
179
|
+
color.white color.black color.gray color.silver color.maroon color.navy
|
|
180
|
+
color.lime color.teal color.aqua color.fuchsia color.olive
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## `syminfo.*` (read-only)
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
syminfo.ticker // "AAPL"
|
|
187
|
+
syminfo.tickerid // "NASDAQ:AAPL"
|
|
188
|
+
syminfo.prefix // "NASDAQ"
|
|
189
|
+
syminfo.description // "Apple Inc."
|
|
190
|
+
syminfo.currency // "USD"
|
|
191
|
+
syminfo.basecurrency
|
|
192
|
+
syminfo.type // "stock", "futures", "crypto", "forex", ...
|
|
193
|
+
syminfo.mintick // minimum price increment
|
|
194
|
+
syminfo.pointvalue
|
|
195
|
+
syminfo.session
|
|
196
|
+
syminfo.timezone
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## `timeframe.*`
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
timeframe.period // current chart TF as string "1", "5", "60", "D", "W"
|
|
203
|
+
timeframe.multiplier
|
|
204
|
+
timeframe.isintraday
|
|
205
|
+
timeframe.isdaily
|
|
206
|
+
timeframe.isweekly
|
|
207
|
+
timeframe.ismonthly
|
|
208
|
+
timeframe.in_seconds(tf = timeframe.period)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## `barstate.*` — see v6-language.md
|
|
212
|
+
|
|
213
|
+
## `alert*`
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
alert(message, freq)
|
|
217
|
+
// freq: alert.freq_once_per_bar, alert.freq_once_per_bar_close, alert.freq_all
|
|
218
|
+
alertcondition(condition, title, message)
|
|
219
|
+
```
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// Title: Webhook-Ready Strategy Template
|
|
3
|
+
// Description:
|
|
4
|
+
// Strategy that emits JSON-shaped alert messages on entry and exit.
|
|
5
|
+
// Pair with TradingView's alert webhook (Pro+ plan) — set the
|
|
6
|
+
// webhook URL to your agent / broker bridge endpoint.
|
|
7
|
+
//
|
|
8
|
+
// Webhook payload contract (per alert):
|
|
9
|
+
// {
|
|
10
|
+
// "action": "buy" | "sell" | "exit_long" | "exit_short",
|
|
11
|
+
// "symbol": "<TICKER>",
|
|
12
|
+
// "price": <float>,
|
|
13
|
+
// "qty": <float>,
|
|
14
|
+
// "time": <unix ms>,
|
|
15
|
+
// "tag": "<strategy-name>"
|
|
16
|
+
// }
|
|
17
|
+
// ─────────────────────────────────────────────────────────────
|
|
18
|
+
//@version=6
|
|
19
|
+
strategy(
|
|
20
|
+
title = "Webhook Strategy",
|
|
21
|
+
overlay = true,
|
|
22
|
+
initial_capital = 10000,
|
|
23
|
+
default_qty_type = strategy.percent_of_equity,
|
|
24
|
+
default_qty_value = 10,
|
|
25
|
+
process_orders_on_close = true
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
fastLen = input.int(10, "Fast")
|
|
29
|
+
slowLen = input.int(30, "Slow")
|
|
30
|
+
tag = input.string("webhook-strat", "Strategy tag")
|
|
31
|
+
|
|
32
|
+
fast = ta.ema(close, fastLen)
|
|
33
|
+
slow = ta.ema(close, slowLen)
|
|
34
|
+
|
|
35
|
+
longCond = ta.crossover(fast, slow)
|
|
36
|
+
shortCond = ta.crossunder(fast, slow)
|
|
37
|
+
|
|
38
|
+
// Build JSON payload helper
|
|
39
|
+
buildPayload(simple string action) =>
|
|
40
|
+
'{' +
|
|
41
|
+
'"action":"' + action + '",' +
|
|
42
|
+
'"symbol":"' + syminfo.ticker + '",' +
|
|
43
|
+
'"price":' + str.tostring(close) + ',' +
|
|
44
|
+
'"qty":' + str.tostring(strategy.position_size) + ',' +
|
|
45
|
+
'"time":' + str.tostring(time) + ',' +
|
|
46
|
+
'"tag":"' + tag + '"' +
|
|
47
|
+
'}'
|
|
48
|
+
|
|
49
|
+
if longCond
|
|
50
|
+
strategy.entry("L", strategy.long)
|
|
51
|
+
alert(buildPayload("buy"), alert.freq_once_per_bar_close)
|
|
52
|
+
|
|
53
|
+
if shortCond
|
|
54
|
+
strategy.entry("S", strategy.short)
|
|
55
|
+
alert(buildPayload("sell"), alert.freq_once_per_bar_close)
|
|
56
|
+
|
|
57
|
+
// Exit on opposite signal
|
|
58
|
+
if strategy.position_size > 0 and shortCond
|
|
59
|
+
alert(buildPayload("exit_long"), alert.freq_once_per_bar_close)
|
|
60
|
+
|
|
61
|
+
if strategy.position_size < 0 and longCond
|
|
62
|
+
alert(buildPayload("exit_short"), alert.freq_once_per_bar_close)
|
|
63
|
+
|
|
64
|
+
plot(fast, "Fast", color=color.aqua)
|
|
65
|
+
plot(slow, "Slow", color=color.orange)
|
|
66
|
+
|
|
67
|
+
// ─────────────────────────────────────────────────────────────
|
|
68
|
+
// HOW TO USE:
|
|
69
|
+
// 1. Save this script in TradingView's Pine Editor.
|
|
70
|
+
// 2. Add to chart. Open the alerts dialog (clock icon).
|
|
71
|
+
// 3. Condition: select this strategy → "Any alert() function call".
|
|
72
|
+
// 4. Notifications → Webhook URL → paste your endpoint
|
|
73
|
+
// (e.g. https://yourdomain.com/tv-webhook)
|
|
74
|
+
// 5. Message: leave blank (the alert() calls in code provide the payload)
|
|
75
|
+
// 6. Save. TradingView will POST the JSON above on each signal.
|
|
76
|
+
// ─────────────────────────────────────────────────────────────
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// Title: <Indicator Name>
|
|
3
|
+
// Author: <user>
|
|
4
|
+
// Description: <one-paragraph description>
|
|
5
|
+
// Version: v6, <date>
|
|
6
|
+
// ─────────────────────────────────────────────────────────────
|
|
7
|
+
//@version=6
|
|
8
|
+
// NOTE: TV's compiler is picky about multi-line function calls — keep the
|
|
9
|
+
// declaration on a single line (or use line continuations with a comma on
|
|
10
|
+
// each line and the closing paren tight on the last line, NO leading space).
|
|
11
|
+
indicator("<Indicator Name>", shorttitle="<short>", overlay=true, max_bars_back=500, max_labels_count=50, max_lines_count=50)
|
|
12
|
+
|
|
13
|
+
// ───── Inputs ────────────────────────────────────────────────
|
|
14
|
+
length = input.int(14, "Length", minval=1, group="Core")
|
|
15
|
+
src = input.source(close, "Source", group="Core")
|
|
16
|
+
smoothing = input.string("EMA", "Smoothing", options=["SMA", "EMA", "RMA", "WMA"], group="Core")
|
|
17
|
+
showSignals = input.bool(true, "Show buy/sell signals", group="Display")
|
|
18
|
+
|
|
19
|
+
// ───── Calculations ──────────────────────────────────────────
|
|
20
|
+
smoothMA(series float source, simple int len, simple string method) =>
|
|
21
|
+
switch method
|
|
22
|
+
"SMA" => ta.sma(source, len)
|
|
23
|
+
"EMA" => ta.ema(source, len)
|
|
24
|
+
"RMA" => ta.rma(source, len)
|
|
25
|
+
"WMA" => ta.wma(source, len)
|
|
26
|
+
=> ta.ema(source, len)
|
|
27
|
+
|
|
28
|
+
basis = smoothMA(src, length, smoothing)
|
|
29
|
+
upper = basis + ta.atr(length)
|
|
30
|
+
lower = basis - ta.atr(length)
|
|
31
|
+
|
|
32
|
+
longSignal = ta.crossover(close, upper)
|
|
33
|
+
shortSignal = ta.crossunder(close, lower)
|
|
34
|
+
|
|
35
|
+
// ───── Plots ─────────────────────────────────────────────────
|
|
36
|
+
plot(basis, "Basis", color=color.new(color.blue, 0), linewidth=2)
|
|
37
|
+
plot(upper, "Upper Band", color=color.new(color.gray, 30))
|
|
38
|
+
plot(lower, "Lower Band", color=color.new(color.gray, 30))
|
|
39
|
+
|
|
40
|
+
plotshape(showSignals and longSignal, "Long", shape.triangleup, location.belowbar, color.lime, size=size.tiny)
|
|
41
|
+
plotshape(showSignals and shortSignal, "Short", shape.triangledown, location.abovebar, color.red, size=size.tiny)
|
|
42
|
+
|
|
43
|
+
bgcolor(longSignal ? color.new(color.lime, 92) : na)
|
|
44
|
+
bgcolor(shortSignal ? color.new(color.red, 92) : na)
|
|
45
|
+
|
|
46
|
+
// ───── Alerts ────────────────────────────────────────────────
|
|
47
|
+
alertcondition(longSignal, "Long signal", "Long signal on {{ticker}} at {{close}}")
|
|
48
|
+
alertcondition(shortSignal, "Short signal", "Short signal on {{ticker}} at {{close}}")
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// Title: <Strategy Name>
|
|
3
|
+
// Author: <user>
|
|
4
|
+
// Description: <one-paragraph description of entry/exit logic>
|
|
5
|
+
// Version: v6, <date>
|
|
6
|
+
// ─────────────────────────────────────────────────────────────
|
|
7
|
+
//@version=6
|
|
8
|
+
// NOTE: keep the declaration on a single line (TV is picky about multi-line
|
|
9
|
+
// function calls). Wrap with line continuations if needed for readability.
|
|
10
|
+
strategy("<Strategy Name>", shorttitle="<short>", overlay=true, initial_capital=10000, currency=currency.USD, default_qty_type=strategy.percent_of_equity, default_qty_value=10, commission_type=strategy.commission.percent, commission_value=0.05, slippage=2, pyramiding=0, process_orders_on_close=true, calc_on_every_tick=false, max_bars_back=500)
|
|
11
|
+
|
|
12
|
+
// ───── Inputs ────────────────────────────────────────────────
|
|
13
|
+
fastLen = input.int(10, "Fast MA", minval=1, group="MA")
|
|
14
|
+
slowLen = input.int(30, "Slow MA", minval=1, group="MA")
|
|
15
|
+
useATRStop = input.bool(true, "Use ATR stop", group="Risk")
|
|
16
|
+
atrLen = input.int(14, "ATR length", minval=1, group="Risk")
|
|
17
|
+
atrMult = input.float(2.0, "ATR multiplier", minval=0.1, step=0.1, group="Risk")
|
|
18
|
+
rrRatio = input.float(2.0, "Reward:Risk", minval=0.1, step=0.1, group="Risk")
|
|
19
|
+
|
|
20
|
+
// Session / time filter (optional)
|
|
21
|
+
useTime = input.bool(false, "Limit to session", group="Time")
|
|
22
|
+
sess = input.session("0930-1600", "Session", group="Time")
|
|
23
|
+
inSession = not useTime or not na(time(timeframe.period, sess))
|
|
24
|
+
|
|
25
|
+
// ───── Calculations ──────────────────────────────────────────
|
|
26
|
+
fastMA = ta.ema(close, fastLen)
|
|
27
|
+
slowMA = ta.ema(close, slowLen)
|
|
28
|
+
atr = ta.atr(atrLen)
|
|
29
|
+
|
|
30
|
+
longCond = ta.crossover(fastMA, slowMA) and inSession
|
|
31
|
+
shortCond = ta.crossunder(fastMA, slowMA) and inSession
|
|
32
|
+
|
|
33
|
+
// ───── Orders ────────────────────────────────────────────────
|
|
34
|
+
if longCond
|
|
35
|
+
stopPx = close - atrMult * atr
|
|
36
|
+
targetPx = close + atrMult * atr * rrRatio
|
|
37
|
+
strategy.entry("L", strategy.long)
|
|
38
|
+
if useATRStop
|
|
39
|
+
strategy.exit("L-exit", from_entry="L", stop=stopPx, limit=targetPx)
|
|
40
|
+
|
|
41
|
+
if shortCond
|
|
42
|
+
stopPx = close + atrMult * atr
|
|
43
|
+
targetPx = close - atrMult * atr * rrRatio
|
|
44
|
+
strategy.entry("S", strategy.short)
|
|
45
|
+
if useATRStop
|
|
46
|
+
strategy.exit("S-exit", from_entry="S", stop=stopPx, limit=targetPx)
|
|
47
|
+
|
|
48
|
+
// ───── Plots ─────────────────────────────────────────────────
|
|
49
|
+
plot(fastMA, "Fast MA", color=color.new(color.aqua, 0))
|
|
50
|
+
plot(slowMA, "Slow MA", color=color.new(color.orange, 0))
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# v5 → v6 migration guide
|
|
2
|
+
|
|
3
|
+
Most v5 code runs unchanged when you bump the version directive, but a few patterns
|
|
4
|
+
need updating. Common compile errors and their fixes:
|
|
5
|
+
|
|
6
|
+
## 1. Generic type constructors
|
|
7
|
+
|
|
8
|
+
```pinescript
|
|
9
|
+
// v5 (still works but deprecated)
|
|
10
|
+
arr = array.new_float(10, 0.0)
|
|
11
|
+
mat = matrix.new_float(3, 3, 0.0)
|
|
12
|
+
|
|
13
|
+
// v6 (preferred)
|
|
14
|
+
arr = array.new<float>(10, 0.0)
|
|
15
|
+
mat = matrix.new<float>(3, 3, 0.0)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Same applies to `int`, `bool`, `string`, `color`, `label`, `line`, `box`, custom types.
|
|
19
|
+
|
|
20
|
+
## 2. Anonymous types in arrays/maps
|
|
21
|
+
|
|
22
|
+
```pinescript
|
|
23
|
+
// v5
|
|
24
|
+
type Bar
|
|
25
|
+
float o
|
|
26
|
+
float c
|
|
27
|
+
|
|
28
|
+
var bars = array.new<Bar>()
|
|
29
|
+
|
|
30
|
+
// v6 — same syntax ✓ but you can now use methods
|
|
31
|
+
method body(Bar self) =>
|
|
32
|
+
math.abs(self.c - self.o)
|
|
33
|
+
|
|
34
|
+
method is_bull(Bar self) =>
|
|
35
|
+
self.c > self.o
|
|
36
|
+
|
|
37
|
+
// Call site
|
|
38
|
+
b = Bar.new(100, 110)
|
|
39
|
+
size = b.body() // method-style
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 3. Boolean optimization changes
|
|
43
|
+
|
|
44
|
+
v6 short-circuits `and`/`or` more aggressively. Side effects in the second operand may
|
|
45
|
+
not execute. Move side effects out:
|
|
46
|
+
|
|
47
|
+
```pinescript
|
|
48
|
+
// v5 may have worked; v6 may skip the second call
|
|
49
|
+
ok = check_a() and (counter := counter + 1) > 0
|
|
50
|
+
|
|
51
|
+
// v6 safe
|
|
52
|
+
a_ok = check_a()
|
|
53
|
+
counter := counter + 1
|
|
54
|
+
ok = a_ok and counter > 0
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 4. `request.security` parameter ordering
|
|
58
|
+
|
|
59
|
+
v6 enforces stricter type checking on the `expression` parameter. If you pass tuples,
|
|
60
|
+
they must use the explicit form:
|
|
61
|
+
|
|
62
|
+
```pinescript
|
|
63
|
+
// v5 — implicit tuple
|
|
64
|
+
[h, l, c] = request.security(sym, "D", [high, low, close])
|
|
65
|
+
|
|
66
|
+
// v6 — same syntax ✓ but each element must be the same series type
|
|
67
|
+
// If you need mixed types, use multiple calls
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 5. `strategy.exit` profit/loss in points vs ticks
|
|
71
|
+
|
|
72
|
+
No behavioral change but stricter validation. Make sure `profit` and `loss` are in
|
|
73
|
+
**points** (price units), or use `profit_percent`/`loss_percent`.
|
|
74
|
+
|
|
75
|
+
## 6. Color transparency
|
|
76
|
+
|
|
77
|
+
`color.new(color.red, 50)` — second arg is 0 (opaque) to 100 (transparent). Same in v6.
|
|
78
|
+
If you used `transp=50` in `plot()`, that param still exists.
|
|
79
|
+
|
|
80
|
+
## 7. Removed / renamed (rare)
|
|
81
|
+
|
|
82
|
+
- `tickerid()` → `ticker.new()` (renamed in v5 already; remove any remaining v4 form)
|
|
83
|
+
- `security()` (unprefixed) → `request.security()` (v5 already, but worth checking)
|
|
84
|
+
- `sma()`, `ema()`, etc. unprefixed → `ta.sma()`, `ta.ema()` (v5 already)
|
|
85
|
+
|
|
86
|
+
## 8. New in v6 (use these if helpful)
|
|
87
|
+
|
|
88
|
+
- **Dynamic requests**: `request.security(sym, tf, expr)` where `sym` can change per bar (with caveats — check official docs)
|
|
89
|
+
- **`chart.point`**: convenience type for line/label coordinates
|
|
90
|
+
- **Polylines**: `polyline.new(points, ...)` for connected segments
|
|
91
|
+
- **Improved `runtime.error()`**: clearer error surfaces
|
|
92
|
+
|
|
93
|
+
## Compile error decoder
|
|
94
|
+
|
|
95
|
+
| Error message | Likely cause |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `Cannot call '...' with arguments (series int, ...)` | Passing series where simple expected. Cast or use `int(x)` if literal. |
|
|
98
|
+
| `Undeclared identifier 'sma'` | Missing `ta.` prefix |
|
|
99
|
+
| `The 'expression' has wrong type` in `request.security` | Mixing series types inside a tuple |
|
|
100
|
+
| `Pine cannot determine the referencing length` | Add `max_bars_back=N` to `indicator()`/`strategy()` |
|
|
101
|
+
| `Function should be called on each calculation` | `var`-initialized inside a conditional; move it out |
|
|
102
|
+
| `Script must have at least one output` | Indicator without any `plot*` / `bgcolor` / `hline` |
|