opencode-pine2pyne 0.1.0__tar.gz → 0.1.1__tar.gz
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.
- opencode_pine2pyne-0.1.1/PKG-INFO +219 -0
- opencode_pine2pyne-0.1.1/README.md +199 -0
- opencode_pine2pyne-0.1.1/opencode_pine2pyne.egg-info/PKG-INFO +219 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/opencode_pine2pyne.egg-info/SOURCES.txt +11 -1
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/__init__.py +1 -1
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/codegen.py +14 -2
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/lexer.py +13 -10
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/parser.py +6 -1
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pyproject.toml +7 -0
- opencode_pine2pyne-0.1.1/tests/test_cli.py +697 -0
- opencode_pine2pyne-0.1.1/tests/test_codegen.py +1139 -0
- opencode_pine2pyne-0.1.1/tests/test_corpus_regression.py +316 -0
- opencode_pine2pyne-0.1.1/tests/test_errors.py +269 -0
- opencode_pine2pyne-0.1.1/tests/test_import_resolver.py +791 -0
- opencode_pine2pyne-0.1.1/tests/test_lexer.py +546 -0
- opencode_pine2pyne-0.1.1/tests/test_parser.py +964 -0
- opencode_pine2pyne-0.1.1/tests/test_pine_builtins.py +661 -0
- opencode_pine2pyne-0.1.1/tests/test_symbol_table.py +451 -0
- opencode_pine2pyne-0.1.1/tests/test_transformer.py +651 -0
- opencode_pine2pyne-0.1.0/PKG-INFO +0 -123
- opencode_pine2pyne-0.1.0/README.md +0 -103
- opencode_pine2pyne-0.1.0/opencode_pine2pyne.egg-info/PKG-INFO +0 -123
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/LICENSE +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/opencode_pine2pyne.egg-info/dependency_links.txt +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/opencode_pine2pyne.egg-info/entry_points.txt +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/opencode_pine2pyne.egg-info/requires.txt +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/opencode_pine2pyne.egg-info/top_level.txt +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/README.md +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/TRANSPILER_BEST_PRACTICES.md +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/TRANSPILER_USAGE.md +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/__main__.py +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/ast_nodes.py +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/cli.py +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/errors.py +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/import_resolver.py +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/pine_builtins.py +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/symbol_table.py +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/tokens.py +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/transformer.py +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/pine2pyne/type_inference.py +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/setup.cfg +0 -0
- {opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/tests/test_screener_regression.py +0 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: opencode-pine2pyne
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Pine Script v6 to PyneCore Python transpiler
|
|
5
|
+
Author: rubycell
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/rubycell/pine2pyne
|
|
8
|
+
Project-URL: Repository, https://github.com/rubycell/pine2pyne
|
|
9
|
+
Keywords: pinescript,tradingview,transpiler,pynecore,backtesting
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Provides-Extra: runtime
|
|
18
|
+
Requires-Dist: opencode-pyneruntime; extra == "runtime"
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# PyneCore - Pine Script to Python Transpiler
|
|
22
|
+
|
|
23
|
+
> **Backlog & known bugs:** [Projects board #10](https://github.com/users/rubycell/projects/10)
|
|
24
|
+
> — open work is in **Backlog** (prioritised P0/P1/P2), shipped work in **Done**.
|
|
25
|
+
> Confirmed unfixed transpiler bugs live there too; several are pinned by strict
|
|
26
|
+
> `xfail` tests (see [Running Tests](#running-tests)).
|
|
27
|
+
|
|
28
|
+
## Installation (New Computer)
|
|
29
|
+
|
|
30
|
+
### Fastest: the sandbox-setup skill
|
|
31
|
+
|
|
32
|
+
From the repo root, run the bundled setup script (idempotent — safe to re-run):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bash .claude/skills/sandbox-setup/setup.sh
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
It builds `.venv`, installs everything below, detects `PINE_CPU_COUNT` /
|
|
39
|
+
`PINE_MAX_WORKERS`, seeds a demo dataset, and runs a smoke test that ends in
|
|
40
|
+
`smoke test : PASS` / `READY`. In Claude Code you can also invoke it as
|
|
41
|
+
`/sandbox-setup`.
|
|
42
|
+
|
|
43
|
+
### Manual (equivalent steps)
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# From the repo root:
|
|
47
|
+
python3 -m venv .venv # 1. virtualenv
|
|
48
|
+
.venv/bin/pip install -e . # 2. this transpiler (editable)
|
|
49
|
+
.venv/bin/pip install 'opencode-pyneruntime[cli]' # 3. PyneCore runtime + `pyne` CLI
|
|
50
|
+
.venv/bin/pip install optuna numpy # 4. optimizer deps (not pulled in by the runtime)
|
|
51
|
+
source .venv/bin/activate # 5. activate (Linux/macOS)
|
|
52
|
+
# .venv\Scripts\activate # (Windows)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Verify the install:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
.venv/bin/python -c "import pynecore, pine2pyne, optuna, numpy; print('all ok')"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Note**: All commands below assume you are at the repo root with the venv activated.
|
|
62
|
+
|
|
63
|
+
## How to Convert Pine Script to Python
|
|
64
|
+
|
|
65
|
+
### Single File Conversion
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
python -m pine2pyne path/to/script.pine -o path/to/output.py
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Batch Conversion
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
python -m pine2pyne "sample/pinescript/*.pine" -o workdir/scripts/
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Running Tests
|
|
78
|
+
|
|
79
|
+
There are **three** independent test systems. They answer different questions,
|
|
80
|
+
so a green run of one says nothing about the others.
|
|
81
|
+
|
|
82
|
+
| System | Question it answers | Runtime |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| **1. Unit tests** (`tests/`, pytest) | Are the transpiler's internals correct? | ~5 s |
|
|
85
|
+
| **2. Sample suites** (`tools/test_all_*.py`) | Does every corpus sample transpile and run? | ~35 s |
|
|
86
|
+
| **3. Ground truth** (`tools/*_ground_truth*`) | Does it produce the *same numbers* as before? | minutes |
|
|
87
|
+
|
|
88
|
+
### 1. Unit tests — pytest
|
|
89
|
+
|
|
90
|
+
2,000+ tests over `pine2pyne/` (93% line / 86% branch coverage).
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
.venv/bin/python -m pytest tests/ --ignore=tests/test_screener_regression.py -q
|
|
94
|
+
|
|
95
|
+
# with coverage
|
|
96
|
+
.venv/bin/python -m pytest tests/ --ignore=tests/test_screener_regression.py \
|
|
97
|
+
--cov=pine2pyne --cov-report=term-missing
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
> `--ignore` is required: `tests/test_screener_regression.py` imports a
|
|
101
|
+
> `screener` module from a **sibling repo** that is absent here, and fails at
|
|
102
|
+
> collection — which aborts the whole run. Tracked as a P0 card on
|
|
103
|
+
> [board #10](https://github.com/users/rubycell/projects/10).
|
|
104
|
+
|
|
105
|
+
Some tests are `@pytest.mark.xfail(strict=True)` and pin **confirmed unfixed
|
|
106
|
+
bugs**, each with a card on [board #10](https://github.com/users/rubycell/projects/10).
|
|
107
|
+
Strict means fixing a bug turns its marker into a failure until the marker is
|
|
108
|
+
removed, so nothing regresses silently in either direction.
|
|
109
|
+
|
|
110
|
+
The highest-priority one is **P0: codegen emits arithmetically wrong Python** —
|
|
111
|
+
`10 - (5 - 3)` transpiles to `10 - 5 - 3`, which evaluates to 2 rather than 8.
|
|
112
|
+
See [docs/test_plan.md](docs/test_plan.md) for the full bug inventory and the
|
|
113
|
+
measured coverage/mutation results.
|
|
114
|
+
|
|
115
|
+
### 2. Sample suites — end-to-end transpile + run
|
|
116
|
+
|
|
117
|
+
Transpiles every `.pine` in the corpus and runs it through `pyne`.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
python tools/test_all_samples.py # sample/pinescript (~411 files)
|
|
121
|
+
python tools/test_all_sample_pds.py # sample_pds (~328 files)
|
|
122
|
+
|
|
123
|
+
python tools/test_all_samples.py "ex_001*" # filter by pattern
|
|
124
|
+
python tools/test_all_samples.py --timeout 30 # default 15s
|
|
125
|
+
python tools/test_all_samples.py --verbose # stderr on failure
|
|
126
|
+
python tools/test_all_samples.py -j 0 # all CPU cores
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
- Source: `sample/pinescript/`, `sample_pds/` · Output: `workdir/scripts/`
|
|
130
|
+
- Data: `workdir/data/demo.ohlcv` · Results: `test_results{,_pds}.{json,txt}`
|
|
131
|
+
|
|
132
|
+
**Per-sample expectations** live in `tools/sample_expectations.toml`:
|
|
133
|
+
|
|
134
|
+
```toml
|
|
135
|
+
[expds_156_Out_of_bounds_index]
|
|
136
|
+
expect_error = "index_error" # MUST raise; running clean = FAIL
|
|
137
|
+
|
|
138
|
+
[ex_300_ticker_modify]
|
|
139
|
+
requires_feeds = { D = "demo", "2D" = "demo_2D" } # -> --security D=demo …
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`expect_error` marks Pine documentation samples that exist to *demonstrate* an
|
|
143
|
+
error — they are reported as `XFAIL` and count as passes. `requires_feeds`
|
|
144
|
+
supplies extra OHLCV feeds for samples calling `request.security()` at a
|
|
145
|
+
timeframe other than the chart's; pynecore deliberately will not resample the
|
|
146
|
+
chart feed, so the feed must be explicit. Generate one with:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
cd workdir && pyne data aggregate data/demo.ohlcv -tf 2D
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Shared logic for both suites lives in `tools/_suite_common.py` — edit it there,
|
|
153
|
+
not in each harness.
|
|
154
|
+
|
|
155
|
+
### 3. Ground truth — numeric regression
|
|
156
|
+
|
|
157
|
+
Diffs freshly generated output CSVs against ~1,985 stored baselines in
|
|
158
|
+
`ground_truth/` (779 MB). This is the only system that catches *silently wrong
|
|
159
|
+
numbers* — output that runs fine but computes something different.
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
python tools/generate_ground_truth.py # (re)build baselines
|
|
163
|
+
python tools/compare_ground_truth.py # diff current output vs baselines
|
|
164
|
+
python tools/compare_ground_truth.py --suite sample_pds -j 12
|
|
165
|
+
./tools/verify_ground_truth.sh # end-to-end wrapper
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
> Regenerate baselines only when you have *confirmed* the new output is correct
|
|
169
|
+
> — otherwise a bug gets frozen in as the expected result.
|
|
170
|
+
|
|
171
|
+
### Test data
|
|
172
|
+
|
|
173
|
+
`workdir/data/` is gitignored, so a fresh clone has none and the sample suites
|
|
174
|
+
abort with `Data file not found`. Restore the exact dataset the recorded results
|
|
175
|
+
were measured against:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
git show 227f3d2^:workdir/data/demo.ohlcv > workdir/data/demo.ohlcv
|
|
179
|
+
git show 227f3d2^:workdir/data/demo.toml > workdir/data/demo.toml
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
(CCXT BTCUSDT 1D. `/sandbox-setup` instead seeds a small *synthetic* fixture —
|
|
183
|
+
fine for a smoke test, but results will not match the recorded rates.)
|
|
184
|
+
|
|
185
|
+
## For Claude Code / LLM Development
|
|
186
|
+
|
|
187
|
+
See `CLAUDE.md` in this directory for transpiler architecture, output format specs, optimizer documentation, and CSV rounding rules. See `pine2pyne/README.md` for transpiler internals and transformation rules.
|
|
188
|
+
|
|
189
|
+
## Optimizing Strategies
|
|
190
|
+
|
|
191
|
+
Quick start: `pyne optimize script.py data.ohlcv params.json -n 20`
|
|
192
|
+
|
|
193
|
+
See [Optimizer.md](./Optimizer.md) for full documentation (parameter JSON format, parallel execution, output files).
|
|
194
|
+
|
|
195
|
+
### Distributed Optimization (multi-machine)
|
|
196
|
+
|
|
197
|
+
Two tools distribute `pyne optimize` across SSH clusters:
|
|
198
|
+
|
|
199
|
+
| Tool | Model | Best for |
|
|
200
|
+
|------|-------|----------|
|
|
201
|
+
| `pyne-dynamic.sh` | Flat-queue (on-demand dispatch) | Multi-variant runs, heterogeneous clusters, long jobs |
|
|
202
|
+
| `pyne-parallel.sh` | Static pre-assignment | Quick jobs on similar-speed machines |
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Dynamic (recommended): flat-queue, pre-syncs once, auto-adapts to machine speed
|
|
206
|
+
# Run from workdir/ directory:
|
|
207
|
+
../tools/pyne-dynamic.sh scripts/strategy.py data/data.ohlcv optimize_variants/ \
|
|
208
|
+
-H ../tools/machines.txt -C 24 --name my_run --output-dir runs/output/
|
|
209
|
+
|
|
210
|
+
# Static: pre-assigns chunks by core count
|
|
211
|
+
./tools/pyne-parallel.sh scripts/strategy.py data/data.ohlcv optimize.json \
|
|
212
|
+
-H tools/machines.txt --sync
|
|
213
|
+
|
|
214
|
+
# Check progress / collect results
|
|
215
|
+
../tools/pyne-dynamic.sh --status
|
|
216
|
+
../tools/pyne-dynamic.sh --collect
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Both use the same `machines.txt` format. See `CLAUDE.md` for cluster setup, machine file format, and troubleshooting.
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# PyneCore - Pine Script to Python Transpiler
|
|
2
|
+
|
|
3
|
+
> **Backlog & known bugs:** [Projects board #10](https://github.com/users/rubycell/projects/10)
|
|
4
|
+
> — open work is in **Backlog** (prioritised P0/P1/P2), shipped work in **Done**.
|
|
5
|
+
> Confirmed unfixed transpiler bugs live there too; several are pinned by strict
|
|
6
|
+
> `xfail` tests (see [Running Tests](#running-tests)).
|
|
7
|
+
|
|
8
|
+
## Installation (New Computer)
|
|
9
|
+
|
|
10
|
+
### Fastest: the sandbox-setup skill
|
|
11
|
+
|
|
12
|
+
From the repo root, run the bundled setup script (idempotent — safe to re-run):
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
bash .claude/skills/sandbox-setup/setup.sh
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
It builds `.venv`, installs everything below, detects `PINE_CPU_COUNT` /
|
|
19
|
+
`PINE_MAX_WORKERS`, seeds a demo dataset, and runs a smoke test that ends in
|
|
20
|
+
`smoke test : PASS` / `READY`. In Claude Code you can also invoke it as
|
|
21
|
+
`/sandbox-setup`.
|
|
22
|
+
|
|
23
|
+
### Manual (equivalent steps)
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# From the repo root:
|
|
27
|
+
python3 -m venv .venv # 1. virtualenv
|
|
28
|
+
.venv/bin/pip install -e . # 2. this transpiler (editable)
|
|
29
|
+
.venv/bin/pip install 'opencode-pyneruntime[cli]' # 3. PyneCore runtime + `pyne` CLI
|
|
30
|
+
.venv/bin/pip install optuna numpy # 4. optimizer deps (not pulled in by the runtime)
|
|
31
|
+
source .venv/bin/activate # 5. activate (Linux/macOS)
|
|
32
|
+
# .venv\Scripts\activate # (Windows)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Verify the install:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
.venv/bin/python -c "import pynecore, pine2pyne, optuna, numpy; print('all ok')"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Note**: All commands below assume you are at the repo root with the venv activated.
|
|
42
|
+
|
|
43
|
+
## How to Convert Pine Script to Python
|
|
44
|
+
|
|
45
|
+
### Single File Conversion
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
python -m pine2pyne path/to/script.pine -o path/to/output.py
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Batch Conversion
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
python -m pine2pyne "sample/pinescript/*.pine" -o workdir/scripts/
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Running Tests
|
|
58
|
+
|
|
59
|
+
There are **three** independent test systems. They answer different questions,
|
|
60
|
+
so a green run of one says nothing about the others.
|
|
61
|
+
|
|
62
|
+
| System | Question it answers | Runtime |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| **1. Unit tests** (`tests/`, pytest) | Are the transpiler's internals correct? | ~5 s |
|
|
65
|
+
| **2. Sample suites** (`tools/test_all_*.py`) | Does every corpus sample transpile and run? | ~35 s |
|
|
66
|
+
| **3. Ground truth** (`tools/*_ground_truth*`) | Does it produce the *same numbers* as before? | minutes |
|
|
67
|
+
|
|
68
|
+
### 1. Unit tests — pytest
|
|
69
|
+
|
|
70
|
+
2,000+ tests over `pine2pyne/` (93% line / 86% branch coverage).
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
.venv/bin/python -m pytest tests/ --ignore=tests/test_screener_regression.py -q
|
|
74
|
+
|
|
75
|
+
# with coverage
|
|
76
|
+
.venv/bin/python -m pytest tests/ --ignore=tests/test_screener_regression.py \
|
|
77
|
+
--cov=pine2pyne --cov-report=term-missing
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
> `--ignore` is required: `tests/test_screener_regression.py` imports a
|
|
81
|
+
> `screener` module from a **sibling repo** that is absent here, and fails at
|
|
82
|
+
> collection — which aborts the whole run. Tracked as a P0 card on
|
|
83
|
+
> [board #10](https://github.com/users/rubycell/projects/10).
|
|
84
|
+
|
|
85
|
+
Some tests are `@pytest.mark.xfail(strict=True)` and pin **confirmed unfixed
|
|
86
|
+
bugs**, each with a card on [board #10](https://github.com/users/rubycell/projects/10).
|
|
87
|
+
Strict means fixing a bug turns its marker into a failure until the marker is
|
|
88
|
+
removed, so nothing regresses silently in either direction.
|
|
89
|
+
|
|
90
|
+
The highest-priority one is **P0: codegen emits arithmetically wrong Python** —
|
|
91
|
+
`10 - (5 - 3)` transpiles to `10 - 5 - 3`, which evaluates to 2 rather than 8.
|
|
92
|
+
See [docs/test_plan.md](docs/test_plan.md) for the full bug inventory and the
|
|
93
|
+
measured coverage/mutation results.
|
|
94
|
+
|
|
95
|
+
### 2. Sample suites — end-to-end transpile + run
|
|
96
|
+
|
|
97
|
+
Transpiles every `.pine` in the corpus and runs it through `pyne`.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
python tools/test_all_samples.py # sample/pinescript (~411 files)
|
|
101
|
+
python tools/test_all_sample_pds.py # sample_pds (~328 files)
|
|
102
|
+
|
|
103
|
+
python tools/test_all_samples.py "ex_001*" # filter by pattern
|
|
104
|
+
python tools/test_all_samples.py --timeout 30 # default 15s
|
|
105
|
+
python tools/test_all_samples.py --verbose # stderr on failure
|
|
106
|
+
python tools/test_all_samples.py -j 0 # all CPU cores
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- Source: `sample/pinescript/`, `sample_pds/` · Output: `workdir/scripts/`
|
|
110
|
+
- Data: `workdir/data/demo.ohlcv` · Results: `test_results{,_pds}.{json,txt}`
|
|
111
|
+
|
|
112
|
+
**Per-sample expectations** live in `tools/sample_expectations.toml`:
|
|
113
|
+
|
|
114
|
+
```toml
|
|
115
|
+
[expds_156_Out_of_bounds_index]
|
|
116
|
+
expect_error = "index_error" # MUST raise; running clean = FAIL
|
|
117
|
+
|
|
118
|
+
[ex_300_ticker_modify]
|
|
119
|
+
requires_feeds = { D = "demo", "2D" = "demo_2D" } # -> --security D=demo …
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`expect_error` marks Pine documentation samples that exist to *demonstrate* an
|
|
123
|
+
error — they are reported as `XFAIL` and count as passes. `requires_feeds`
|
|
124
|
+
supplies extra OHLCV feeds for samples calling `request.security()` at a
|
|
125
|
+
timeframe other than the chart's; pynecore deliberately will not resample the
|
|
126
|
+
chart feed, so the feed must be explicit. Generate one with:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
cd workdir && pyne data aggregate data/demo.ohlcv -tf 2D
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Shared logic for both suites lives in `tools/_suite_common.py` — edit it there,
|
|
133
|
+
not in each harness.
|
|
134
|
+
|
|
135
|
+
### 3. Ground truth — numeric regression
|
|
136
|
+
|
|
137
|
+
Diffs freshly generated output CSVs against ~1,985 stored baselines in
|
|
138
|
+
`ground_truth/` (779 MB). This is the only system that catches *silently wrong
|
|
139
|
+
numbers* — output that runs fine but computes something different.
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
python tools/generate_ground_truth.py # (re)build baselines
|
|
143
|
+
python tools/compare_ground_truth.py # diff current output vs baselines
|
|
144
|
+
python tools/compare_ground_truth.py --suite sample_pds -j 12
|
|
145
|
+
./tools/verify_ground_truth.sh # end-to-end wrapper
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
> Regenerate baselines only when you have *confirmed* the new output is correct
|
|
149
|
+
> — otherwise a bug gets frozen in as the expected result.
|
|
150
|
+
|
|
151
|
+
### Test data
|
|
152
|
+
|
|
153
|
+
`workdir/data/` is gitignored, so a fresh clone has none and the sample suites
|
|
154
|
+
abort with `Data file not found`. Restore the exact dataset the recorded results
|
|
155
|
+
were measured against:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
git show 227f3d2^:workdir/data/demo.ohlcv > workdir/data/demo.ohlcv
|
|
159
|
+
git show 227f3d2^:workdir/data/demo.toml > workdir/data/demo.toml
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
(CCXT BTCUSDT 1D. `/sandbox-setup` instead seeds a small *synthetic* fixture —
|
|
163
|
+
fine for a smoke test, but results will not match the recorded rates.)
|
|
164
|
+
|
|
165
|
+
## For Claude Code / LLM Development
|
|
166
|
+
|
|
167
|
+
See `CLAUDE.md` in this directory for transpiler architecture, output format specs, optimizer documentation, and CSV rounding rules. See `pine2pyne/README.md` for transpiler internals and transformation rules.
|
|
168
|
+
|
|
169
|
+
## Optimizing Strategies
|
|
170
|
+
|
|
171
|
+
Quick start: `pyne optimize script.py data.ohlcv params.json -n 20`
|
|
172
|
+
|
|
173
|
+
See [Optimizer.md](./Optimizer.md) for full documentation (parameter JSON format, parallel execution, output files).
|
|
174
|
+
|
|
175
|
+
### Distributed Optimization (multi-machine)
|
|
176
|
+
|
|
177
|
+
Two tools distribute `pyne optimize` across SSH clusters:
|
|
178
|
+
|
|
179
|
+
| Tool | Model | Best for |
|
|
180
|
+
|------|-------|----------|
|
|
181
|
+
| `pyne-dynamic.sh` | Flat-queue (on-demand dispatch) | Multi-variant runs, heterogeneous clusters, long jobs |
|
|
182
|
+
| `pyne-parallel.sh` | Static pre-assignment | Quick jobs on similar-speed machines |
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# Dynamic (recommended): flat-queue, pre-syncs once, auto-adapts to machine speed
|
|
186
|
+
# Run from workdir/ directory:
|
|
187
|
+
../tools/pyne-dynamic.sh scripts/strategy.py data/data.ohlcv optimize_variants/ \
|
|
188
|
+
-H ../tools/machines.txt -C 24 --name my_run --output-dir runs/output/
|
|
189
|
+
|
|
190
|
+
# Static: pre-assigns chunks by core count
|
|
191
|
+
./tools/pyne-parallel.sh scripts/strategy.py data/data.ohlcv optimize.json \
|
|
192
|
+
-H tools/machines.txt --sync
|
|
193
|
+
|
|
194
|
+
# Check progress / collect results
|
|
195
|
+
../tools/pyne-dynamic.sh --status
|
|
196
|
+
../tools/pyne-dynamic.sh --collect
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Both use the same `machines.txt` format. See `CLAUDE.md` for cluster setup, machine file format, and troubleshooting.
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: opencode-pine2pyne
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Pine Script v6 to PyneCore Python transpiler
|
|
5
|
+
Author: rubycell
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/rubycell/pine2pyne
|
|
8
|
+
Project-URL: Repository, https://github.com/rubycell/pine2pyne
|
|
9
|
+
Keywords: pinescript,tradingview,transpiler,pynecore,backtesting
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Provides-Extra: runtime
|
|
18
|
+
Requires-Dist: opencode-pyneruntime; extra == "runtime"
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# PyneCore - Pine Script to Python Transpiler
|
|
22
|
+
|
|
23
|
+
> **Backlog & known bugs:** [Projects board #10](https://github.com/users/rubycell/projects/10)
|
|
24
|
+
> — open work is in **Backlog** (prioritised P0/P1/P2), shipped work in **Done**.
|
|
25
|
+
> Confirmed unfixed transpiler bugs live there too; several are pinned by strict
|
|
26
|
+
> `xfail` tests (see [Running Tests](#running-tests)).
|
|
27
|
+
|
|
28
|
+
## Installation (New Computer)
|
|
29
|
+
|
|
30
|
+
### Fastest: the sandbox-setup skill
|
|
31
|
+
|
|
32
|
+
From the repo root, run the bundled setup script (idempotent — safe to re-run):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bash .claude/skills/sandbox-setup/setup.sh
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
It builds `.venv`, installs everything below, detects `PINE_CPU_COUNT` /
|
|
39
|
+
`PINE_MAX_WORKERS`, seeds a demo dataset, and runs a smoke test that ends in
|
|
40
|
+
`smoke test : PASS` / `READY`. In Claude Code you can also invoke it as
|
|
41
|
+
`/sandbox-setup`.
|
|
42
|
+
|
|
43
|
+
### Manual (equivalent steps)
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# From the repo root:
|
|
47
|
+
python3 -m venv .venv # 1. virtualenv
|
|
48
|
+
.venv/bin/pip install -e . # 2. this transpiler (editable)
|
|
49
|
+
.venv/bin/pip install 'opencode-pyneruntime[cli]' # 3. PyneCore runtime + `pyne` CLI
|
|
50
|
+
.venv/bin/pip install optuna numpy # 4. optimizer deps (not pulled in by the runtime)
|
|
51
|
+
source .venv/bin/activate # 5. activate (Linux/macOS)
|
|
52
|
+
# .venv\Scripts\activate # (Windows)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Verify the install:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
.venv/bin/python -c "import pynecore, pine2pyne, optuna, numpy; print('all ok')"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Note**: All commands below assume you are at the repo root with the venv activated.
|
|
62
|
+
|
|
63
|
+
## How to Convert Pine Script to Python
|
|
64
|
+
|
|
65
|
+
### Single File Conversion
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
python -m pine2pyne path/to/script.pine -o path/to/output.py
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Batch Conversion
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
python -m pine2pyne "sample/pinescript/*.pine" -o workdir/scripts/
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Running Tests
|
|
78
|
+
|
|
79
|
+
There are **three** independent test systems. They answer different questions,
|
|
80
|
+
so a green run of one says nothing about the others.
|
|
81
|
+
|
|
82
|
+
| System | Question it answers | Runtime |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| **1. Unit tests** (`tests/`, pytest) | Are the transpiler's internals correct? | ~5 s |
|
|
85
|
+
| **2. Sample suites** (`tools/test_all_*.py`) | Does every corpus sample transpile and run? | ~35 s |
|
|
86
|
+
| **3. Ground truth** (`tools/*_ground_truth*`) | Does it produce the *same numbers* as before? | minutes |
|
|
87
|
+
|
|
88
|
+
### 1. Unit tests — pytest
|
|
89
|
+
|
|
90
|
+
2,000+ tests over `pine2pyne/` (93% line / 86% branch coverage).
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
.venv/bin/python -m pytest tests/ --ignore=tests/test_screener_regression.py -q
|
|
94
|
+
|
|
95
|
+
# with coverage
|
|
96
|
+
.venv/bin/python -m pytest tests/ --ignore=tests/test_screener_regression.py \
|
|
97
|
+
--cov=pine2pyne --cov-report=term-missing
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
> `--ignore` is required: `tests/test_screener_regression.py` imports a
|
|
101
|
+
> `screener` module from a **sibling repo** that is absent here, and fails at
|
|
102
|
+
> collection — which aborts the whole run. Tracked as a P0 card on
|
|
103
|
+
> [board #10](https://github.com/users/rubycell/projects/10).
|
|
104
|
+
|
|
105
|
+
Some tests are `@pytest.mark.xfail(strict=True)` and pin **confirmed unfixed
|
|
106
|
+
bugs**, each with a card on [board #10](https://github.com/users/rubycell/projects/10).
|
|
107
|
+
Strict means fixing a bug turns its marker into a failure until the marker is
|
|
108
|
+
removed, so nothing regresses silently in either direction.
|
|
109
|
+
|
|
110
|
+
The highest-priority one is **P0: codegen emits arithmetically wrong Python** —
|
|
111
|
+
`10 - (5 - 3)` transpiles to `10 - 5 - 3`, which evaluates to 2 rather than 8.
|
|
112
|
+
See [docs/test_plan.md](docs/test_plan.md) for the full bug inventory and the
|
|
113
|
+
measured coverage/mutation results.
|
|
114
|
+
|
|
115
|
+
### 2. Sample suites — end-to-end transpile + run
|
|
116
|
+
|
|
117
|
+
Transpiles every `.pine` in the corpus and runs it through `pyne`.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
python tools/test_all_samples.py # sample/pinescript (~411 files)
|
|
121
|
+
python tools/test_all_sample_pds.py # sample_pds (~328 files)
|
|
122
|
+
|
|
123
|
+
python tools/test_all_samples.py "ex_001*" # filter by pattern
|
|
124
|
+
python tools/test_all_samples.py --timeout 30 # default 15s
|
|
125
|
+
python tools/test_all_samples.py --verbose # stderr on failure
|
|
126
|
+
python tools/test_all_samples.py -j 0 # all CPU cores
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
- Source: `sample/pinescript/`, `sample_pds/` · Output: `workdir/scripts/`
|
|
130
|
+
- Data: `workdir/data/demo.ohlcv` · Results: `test_results{,_pds}.{json,txt}`
|
|
131
|
+
|
|
132
|
+
**Per-sample expectations** live in `tools/sample_expectations.toml`:
|
|
133
|
+
|
|
134
|
+
```toml
|
|
135
|
+
[expds_156_Out_of_bounds_index]
|
|
136
|
+
expect_error = "index_error" # MUST raise; running clean = FAIL
|
|
137
|
+
|
|
138
|
+
[ex_300_ticker_modify]
|
|
139
|
+
requires_feeds = { D = "demo", "2D" = "demo_2D" } # -> --security D=demo …
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`expect_error` marks Pine documentation samples that exist to *demonstrate* an
|
|
143
|
+
error — they are reported as `XFAIL` and count as passes. `requires_feeds`
|
|
144
|
+
supplies extra OHLCV feeds for samples calling `request.security()` at a
|
|
145
|
+
timeframe other than the chart's; pynecore deliberately will not resample the
|
|
146
|
+
chart feed, so the feed must be explicit. Generate one with:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
cd workdir && pyne data aggregate data/demo.ohlcv -tf 2D
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Shared logic for both suites lives in `tools/_suite_common.py` — edit it there,
|
|
153
|
+
not in each harness.
|
|
154
|
+
|
|
155
|
+
### 3. Ground truth — numeric regression
|
|
156
|
+
|
|
157
|
+
Diffs freshly generated output CSVs against ~1,985 stored baselines in
|
|
158
|
+
`ground_truth/` (779 MB). This is the only system that catches *silently wrong
|
|
159
|
+
numbers* — output that runs fine but computes something different.
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
python tools/generate_ground_truth.py # (re)build baselines
|
|
163
|
+
python tools/compare_ground_truth.py # diff current output vs baselines
|
|
164
|
+
python tools/compare_ground_truth.py --suite sample_pds -j 12
|
|
165
|
+
./tools/verify_ground_truth.sh # end-to-end wrapper
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
> Regenerate baselines only when you have *confirmed* the new output is correct
|
|
169
|
+
> — otherwise a bug gets frozen in as the expected result.
|
|
170
|
+
|
|
171
|
+
### Test data
|
|
172
|
+
|
|
173
|
+
`workdir/data/` is gitignored, so a fresh clone has none and the sample suites
|
|
174
|
+
abort with `Data file not found`. Restore the exact dataset the recorded results
|
|
175
|
+
were measured against:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
git show 227f3d2^:workdir/data/demo.ohlcv > workdir/data/demo.ohlcv
|
|
179
|
+
git show 227f3d2^:workdir/data/demo.toml > workdir/data/demo.toml
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
(CCXT BTCUSDT 1D. `/sandbox-setup` instead seeds a small *synthetic* fixture —
|
|
183
|
+
fine for a smoke test, but results will not match the recorded rates.)
|
|
184
|
+
|
|
185
|
+
## For Claude Code / LLM Development
|
|
186
|
+
|
|
187
|
+
See `CLAUDE.md` in this directory for transpiler architecture, output format specs, optimizer documentation, and CSV rounding rules. See `pine2pyne/README.md` for transpiler internals and transformation rules.
|
|
188
|
+
|
|
189
|
+
## Optimizing Strategies
|
|
190
|
+
|
|
191
|
+
Quick start: `pyne optimize script.py data.ohlcv params.json -n 20`
|
|
192
|
+
|
|
193
|
+
See [Optimizer.md](./Optimizer.md) for full documentation (parameter JSON format, parallel execution, output files).
|
|
194
|
+
|
|
195
|
+
### Distributed Optimization (multi-machine)
|
|
196
|
+
|
|
197
|
+
Two tools distribute `pyne optimize` across SSH clusters:
|
|
198
|
+
|
|
199
|
+
| Tool | Model | Best for |
|
|
200
|
+
|------|-------|----------|
|
|
201
|
+
| `pyne-dynamic.sh` | Flat-queue (on-demand dispatch) | Multi-variant runs, heterogeneous clusters, long jobs |
|
|
202
|
+
| `pyne-parallel.sh` | Static pre-assignment | Quick jobs on similar-speed machines |
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Dynamic (recommended): flat-queue, pre-syncs once, auto-adapts to machine speed
|
|
206
|
+
# Run from workdir/ directory:
|
|
207
|
+
../tools/pyne-dynamic.sh scripts/strategy.py data/data.ohlcv optimize_variants/ \
|
|
208
|
+
-H ../tools/machines.txt -C 24 --name my_run --output-dir runs/output/
|
|
209
|
+
|
|
210
|
+
# Static: pre-assigns chunks by core count
|
|
211
|
+
./tools/pyne-parallel.sh scripts/strategy.py data/data.ohlcv optimize.json \
|
|
212
|
+
-H tools/machines.txt --sync
|
|
213
|
+
|
|
214
|
+
# Check progress / collect results
|
|
215
|
+
../tools/pyne-dynamic.sh --status
|
|
216
|
+
../tools/pyne-dynamic.sh --collect
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Both use the same `machines.txt` format. See `CLAUDE.md` for cluster setup, machine file format, and troubleshooting.
|
{opencode_pine2pyne-0.1.0 → opencode_pine2pyne-0.1.1}/opencode_pine2pyne.egg-info/SOURCES.txt
RENAMED
|
@@ -24,4 +24,14 @@ pine2pyne/symbol_table.py
|
|
|
24
24
|
pine2pyne/tokens.py
|
|
25
25
|
pine2pyne/transformer.py
|
|
26
26
|
pine2pyne/type_inference.py
|
|
27
|
-
tests/
|
|
27
|
+
tests/test_cli.py
|
|
28
|
+
tests/test_codegen.py
|
|
29
|
+
tests/test_corpus_regression.py
|
|
30
|
+
tests/test_errors.py
|
|
31
|
+
tests/test_import_resolver.py
|
|
32
|
+
tests/test_lexer.py
|
|
33
|
+
tests/test_parser.py
|
|
34
|
+
tests/test_pine_builtins.py
|
|
35
|
+
tests/test_screener_regression.py
|
|
36
|
+
tests/test_symbol_table.py
|
|
37
|
+
tests/test_transformer.py
|
|
@@ -799,9 +799,21 @@ class CodeGenerator:
|
|
|
799
799
|
return f'{obj}[{index}]'
|
|
800
800
|
|
|
801
801
|
def generate_array_literal(self, expr: ArrayLiteral) -> str:
|
|
802
|
-
"""Generate
|
|
802
|
+
"""Generate a Pine tuple expression as a Python tuple.
|
|
803
|
+
|
|
804
|
+
Pine writes tuple literals with square brackets and has no bracket
|
|
805
|
+
syntax for arrays -- those come from ``array.new``/``array.from`` -- so
|
|
806
|
+
every bracket that reaches here is a tuple, never a collection literal.
|
|
807
|
+
Emitting a list instead makes the runtime take its array branch: it
|
|
808
|
+
answers ``request.seed``/``request.security`` with a single ``na``
|
|
809
|
+
rather than one ``na`` per element, and the caller's destructuring then
|
|
810
|
+
dies with "na is not iterable".
|
|
811
|
+
"""
|
|
803
812
|
elements = [self.generate_expression(e) for e in expr.elements]
|
|
804
|
-
|
|
813
|
+
if len(elements) == 1:
|
|
814
|
+
# A lone parenthesised value is not a tuple without the comma.
|
|
815
|
+
return f'({elements[0]},)'
|
|
816
|
+
return f'({", ".join(elements)})'
|
|
805
817
|
|
|
806
818
|
def _escape_string(self, value: str, quote: str) -> str:
|
|
807
819
|
"""Escape a string value for Python output."""
|