marketschema 1.1.0__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.
- marketschema-1.1.0/PKG-INFO +99 -0
- marketschema-1.1.0/README.md +65 -0
- marketschema-1.1.0/examples/__init__.py +1 -0
- marketschema-1.1.0/examples/paper_bot.py +138 -0
- marketschema-1.1.0/examples/replay_bot.py +142 -0
- marketschema-1.1.0/examples/shadow_bot.py +152 -0
- marketschema-1.1.0/marketschema/__init__.py +36 -0
- marketschema-1.1.0/marketschema/client.py +466 -0
- marketschema-1.1.0/marketschema/paper_bot/__init__.py +51 -0
- marketschema-1.1.0/marketschema/paper_bot/consistency.py +352 -0
- marketschema-1.1.0/marketschema/paper_bot/guardrails.py +256 -0
- marketschema-1.1.0/marketschema/paper_bot/journal.py +91 -0
- marketschema-1.1.0/marketschema/paper_bot/models.py +244 -0
- marketschema-1.1.0/marketschema/paper_bot/provider.py +278 -0
- marketschema-1.1.0/marketschema/paper_bot/runner.py +319 -0
- marketschema-1.1.0/marketschema.egg-info/PKG-INFO +99 -0
- marketschema-1.1.0/marketschema.egg-info/SOURCES.txt +20 -0
- marketschema-1.1.0/marketschema.egg-info/dependency_links.txt +1 -0
- marketschema-1.1.0/marketschema.egg-info/requires.txt +1 -0
- marketschema-1.1.0/marketschema.egg-info/top_level.txt +2 -0
- marketschema-1.1.0/setup.cfg +4 -0
- marketschema-1.1.0/setup.py +36 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: marketschema
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Python SDK for the MarketSchema Public API v1
|
|
5
|
+
Home-page: https://github.com/FlyingMobula5/MarketSchema
|
|
6
|
+
Author: MarketSchema
|
|
7
|
+
Author-email: api@marketschema.com
|
|
8
|
+
Project-URL: Documentation, https://marketschema.com/docs
|
|
9
|
+
Project-URL: Public API, https://marketschema.com/docs/api
|
|
10
|
+
Project-URL: Source, https://github.com/FlyingMobula5/MarketSchema/tree/main/sdk/python
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
20
|
+
Classifier: Topic :: Internet
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
Requires-Dist: requests>=2.28.0
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: author-email
|
|
26
|
+
Dynamic: classifier
|
|
27
|
+
Dynamic: description
|
|
28
|
+
Dynamic: description-content-type
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: project-url
|
|
31
|
+
Dynamic: requires-dist
|
|
32
|
+
Dynamic: requires-python
|
|
33
|
+
Dynamic: summary
|
|
34
|
+
|
|
35
|
+
# MarketSchema Python SDK
|
|
36
|
+
|
|
37
|
+
Official Python client for the [MarketSchema](https://marketschema.com) Public API v1 —
|
|
38
|
+
structural market intelligence: schema scores, market-risk gauges, proprietary indexes,
|
|
39
|
+
narratives, and themes, built for both humans and trading agents.
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install marketschema
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quickstart
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from marketschema import MarketSchemaClient
|
|
51
|
+
|
|
52
|
+
client = MarketSchemaClient(api_key="ms_...") # mint a free key at marketschema.com/account/api-keys
|
|
53
|
+
|
|
54
|
+
# Who am I / what can my key do?
|
|
55
|
+
print(client.whoami())
|
|
56
|
+
print(client.capabilities())
|
|
57
|
+
|
|
58
|
+
# Single-asset intelligence packet
|
|
59
|
+
nvda = client.asset("NVDA")
|
|
60
|
+
print(nvda["schema_score"], nvda["regime_label"])
|
|
61
|
+
|
|
62
|
+
# Batch check (paid tiers)
|
|
63
|
+
result = client.batch(["NVDA", "MSFT", "SPY"])
|
|
64
|
+
|
|
65
|
+
# Server-sent event stream of live updates
|
|
66
|
+
for event in client.stream():
|
|
67
|
+
print(event)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Agent / bot endpoints
|
|
71
|
+
|
|
72
|
+
The SDK speaks the full bot contract — registration, heartbeats, snapshots,
|
|
73
|
+
webhooks, and the paper/replay/shadow harnesses:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
client.register(name="my-bot", environment="paper")
|
|
77
|
+
client.heartbeat(status="ok")
|
|
78
|
+
client.webhook_register(url="https://example.com/hook", events=["score.changed"])
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Complete, runnable agents live in
|
|
82
|
+
[`examples/`](https://github.com/FlyingMobula5/MarketSchema/tree/main/sdk/python/examples)
|
|
83
|
+
(`paper_bot.py`, `replay_bot.py`, `shadow_bot.py`).
|
|
84
|
+
|
|
85
|
+
## Auth, limits, errors
|
|
86
|
+
|
|
87
|
+
- Auth is a single `X-API-Key` header — the client sets it for you.
|
|
88
|
+
- Free tier: 1 key, 60 requests/min. Paid tiers raise key counts, rate
|
|
89
|
+
limits, and batch quotas — see [marketschema.com/pricing](https://marketschema.com/pricing).
|
|
90
|
+
- Non-2xx responses raise `MarketSchemaError` with `.status_code` and the
|
|
91
|
+
parsed error envelope on `.response`.
|
|
92
|
+
|
|
93
|
+
## Links
|
|
94
|
+
|
|
95
|
+
- Docs: https://marketschema.com/docs
|
|
96
|
+
- API reference: https://marketschema.com/docs/api
|
|
97
|
+
- Source: https://github.com/FlyingMobula5/MarketSchema/tree/main/sdk/python
|
|
98
|
+
|
|
99
|
+
MIT licensed.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# MarketSchema Python SDK
|
|
2
|
+
|
|
3
|
+
Official Python client for the [MarketSchema](https://marketschema.com) Public API v1 —
|
|
4
|
+
structural market intelligence: schema scores, market-risk gauges, proprietary indexes,
|
|
5
|
+
narratives, and themes, built for both humans and trading agents.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install marketschema
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from marketschema import MarketSchemaClient
|
|
17
|
+
|
|
18
|
+
client = MarketSchemaClient(api_key="ms_...") # mint a free key at marketschema.com/account/api-keys
|
|
19
|
+
|
|
20
|
+
# Who am I / what can my key do?
|
|
21
|
+
print(client.whoami())
|
|
22
|
+
print(client.capabilities())
|
|
23
|
+
|
|
24
|
+
# Single-asset intelligence packet
|
|
25
|
+
nvda = client.asset("NVDA")
|
|
26
|
+
print(nvda["schema_score"], nvda["regime_label"])
|
|
27
|
+
|
|
28
|
+
# Batch check (paid tiers)
|
|
29
|
+
result = client.batch(["NVDA", "MSFT", "SPY"])
|
|
30
|
+
|
|
31
|
+
# Server-sent event stream of live updates
|
|
32
|
+
for event in client.stream():
|
|
33
|
+
print(event)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Agent / bot endpoints
|
|
37
|
+
|
|
38
|
+
The SDK speaks the full bot contract — registration, heartbeats, snapshots,
|
|
39
|
+
webhooks, and the paper/replay/shadow harnesses:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
client.register(name="my-bot", environment="paper")
|
|
43
|
+
client.heartbeat(status="ok")
|
|
44
|
+
client.webhook_register(url="https://example.com/hook", events=["score.changed"])
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Complete, runnable agents live in
|
|
48
|
+
[`examples/`](https://github.com/FlyingMobula5/MarketSchema/tree/main/sdk/python/examples)
|
|
49
|
+
(`paper_bot.py`, `replay_bot.py`, `shadow_bot.py`).
|
|
50
|
+
|
|
51
|
+
## Auth, limits, errors
|
|
52
|
+
|
|
53
|
+
- Auth is a single `X-API-Key` header — the client sets it for you.
|
|
54
|
+
- Free tier: 1 key, 60 requests/min. Paid tiers raise key counts, rate
|
|
55
|
+
limits, and batch quotas — see [marketschema.com/pricing](https://marketschema.com/pricing).
|
|
56
|
+
- Non-2xx responses raise `MarketSchemaError` with `.status_code` and the
|
|
57
|
+
parsed error envelope on `.response`.
|
|
58
|
+
|
|
59
|
+
## Links
|
|
60
|
+
|
|
61
|
+
- Docs: https://marketschema.com/docs
|
|
62
|
+
- API reference: https://marketschema.com/docs/api
|
|
63
|
+
- Source: https://github.com/FlyingMobula5/MarketSchema/tree/main/sdk/python
|
|
64
|
+
|
|
65
|
+
MIT licensed.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Sprint 17 (#94): Make examples package importable for `python -m examples.paper_bot`
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""MarketSchema Paper Bot — Live Polling Reference
|
|
3
|
+
|
|
4
|
+
Canonical happy-path runner for paper-trading against the MarketSchema API.
|
|
5
|
+
Uses the in-repo SDK and paper_bot adapter layer.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
# Set your API key
|
|
9
|
+
export MS_API_KEY="ms_live_..."
|
|
10
|
+
|
|
11
|
+
# Run 10 cycles at 60-second intervals (default)
|
|
12
|
+
python -m examples.paper_bot
|
|
13
|
+
|
|
14
|
+
# Custom watchlist and cycle count
|
|
15
|
+
python -m examples.paper_bot --watchlist AAPL,MSFT,NVDA,TSLA --cycles 20 --interval 30
|
|
16
|
+
|
|
17
|
+
# With custom journal output
|
|
18
|
+
python -m examples.paper_bot --journal paper_decisions.jsonl
|
|
19
|
+
|
|
20
|
+
Environment Variables:
|
|
21
|
+
MS_API_KEY Required. Your MarketSchema API key.
|
|
22
|
+
MS_BASE_URL Optional. API base URL (default: https://api.marketschema.com).
|
|
23
|
+
|
|
24
|
+
Output:
|
|
25
|
+
- JSONL decision journal (default: output/paper_journal_{date}.jsonl)
|
|
26
|
+
- Summary printed to stderr after completion
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import argparse
|
|
32
|
+
import os
|
|
33
|
+
import sys
|
|
34
|
+
from datetime import datetime, timezone
|
|
35
|
+
|
|
36
|
+
# Allow running from sdk/python/ or repo root
|
|
37
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
38
|
+
|
|
39
|
+
from marketschema import MarketSchemaClient
|
|
40
|
+
from marketschema.paper_bot import PaperBotRunner
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def main() -> None:
|
|
44
|
+
parser = argparse.ArgumentParser(
|
|
45
|
+
description="MarketSchema Paper Bot — live polling reference"
|
|
46
|
+
)
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"--watchlist",
|
|
49
|
+
default="SPY,QQQ,AAPL,MSFT,NVDA",
|
|
50
|
+
help="Comma-separated ticker watchlist (default: SPY,QQQ,AAPL,MSFT,NVDA)",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"--cycles",
|
|
54
|
+
type=int,
|
|
55
|
+
default=10,
|
|
56
|
+
help="Number of polling cycles (default: 10)",
|
|
57
|
+
)
|
|
58
|
+
parser.add_argument(
|
|
59
|
+
"--interval",
|
|
60
|
+
type=int,
|
|
61
|
+
default=60,
|
|
62
|
+
help="Seconds between polls (default: 60)",
|
|
63
|
+
)
|
|
64
|
+
parser.add_argument(
|
|
65
|
+
"--horizon",
|
|
66
|
+
default="swing",
|
|
67
|
+
choices=["day", "swing", "position"],
|
|
68
|
+
help="Trading horizon for batch checks (default: swing)",
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument(
|
|
71
|
+
"--style",
|
|
72
|
+
default=None,
|
|
73
|
+
help="Trading style for batch checks (e.g., momentum, mean_reversion)",
|
|
74
|
+
)
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
"--journal",
|
|
77
|
+
default=None,
|
|
78
|
+
help="Journal output path (default: output/paper_journal_{date}.jsonl)",
|
|
79
|
+
)
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"--bot-name",
|
|
82
|
+
default="ms-paper-bot",
|
|
83
|
+
help="Bot registration name (default: ms-paper-bot)",
|
|
84
|
+
)
|
|
85
|
+
parser.add_argument(
|
|
86
|
+
"--strategy-label",
|
|
87
|
+
default=None,
|
|
88
|
+
help="Strategy label for bot registration",
|
|
89
|
+
)
|
|
90
|
+
args = parser.parse_args()
|
|
91
|
+
|
|
92
|
+
# Validate API key
|
|
93
|
+
api_key = os.environ.get("MS_API_KEY")
|
|
94
|
+
if not api_key:
|
|
95
|
+
print("ERROR: MS_API_KEY environment variable is required.", file=sys.stderr)
|
|
96
|
+
print(" export MS_API_KEY='ms_live_...'", file=sys.stderr)
|
|
97
|
+
sys.exit(1)
|
|
98
|
+
|
|
99
|
+
base_url = os.environ.get("MS_BASE_URL", "https://api.marketschema.com")
|
|
100
|
+
|
|
101
|
+
# Default journal path
|
|
102
|
+
journal_path = args.journal
|
|
103
|
+
if not journal_path:
|
|
104
|
+
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
105
|
+
journal_path = f"output/paper_journal_{today}.jsonl"
|
|
106
|
+
|
|
107
|
+
# Build client and runner
|
|
108
|
+
client = MarketSchemaClient(api_key=api_key, base_url=base_url)
|
|
109
|
+
watchlist = [t.strip() for t in args.watchlist.split(",")]
|
|
110
|
+
|
|
111
|
+
runner = PaperBotRunner.from_client(
|
|
112
|
+
client=client,
|
|
113
|
+
watchlist=watchlist,
|
|
114
|
+
horizon=args.horizon,
|
|
115
|
+
style=args.style,
|
|
116
|
+
journal_path=journal_path,
|
|
117
|
+
bot_name=args.bot_name,
|
|
118
|
+
strategy_label=args.strategy_label,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
print(f"Paper Bot starting:", file=sys.stderr)
|
|
122
|
+
print(f" Watchlist: {watchlist}", file=sys.stderr)
|
|
123
|
+
print(f" Cycles: {args.cycles}", file=sys.stderr)
|
|
124
|
+
print(f" Interval: {args.interval}s", file=sys.stderr)
|
|
125
|
+
print(f" Journal: {journal_path}", file=sys.stderr)
|
|
126
|
+
print(f" Mode: PAPER (no broker, no execution)", file=sys.stderr)
|
|
127
|
+
print(file=sys.stderr)
|
|
128
|
+
|
|
129
|
+
summary = runner.run(cycles=args.cycles, interval=args.interval)
|
|
130
|
+
|
|
131
|
+
print(file=sys.stderr)
|
|
132
|
+
print(f"Run complete. {summary['cycles_completed']} cycles logged to {journal_path}", file=sys.stderr)
|
|
133
|
+
if summary.get("setup_report_path"):
|
|
134
|
+
print(f"Setup report: {summary['setup_report_path']}", file=sys.stderr)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
main()
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""MarketSchema Replay Bot — Historical State Replay Reference
|
|
3
|
+
|
|
4
|
+
Replays historical MarketSchema exports through the same paper-bot logic
|
|
5
|
+
to validate integration behavior against known market states.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
# Replay a saved history/daily export
|
|
9
|
+
python -m examples.replay_bot --source exports/history_2026-03-01_2026-03-07.json
|
|
10
|
+
|
|
11
|
+
# Fetch fresh history from the API, then replay
|
|
12
|
+
python -m examples.replay_bot --fetch --start 2026-03-01 --end 2026-03-07
|
|
13
|
+
|
|
14
|
+
# With custom journal output
|
|
15
|
+
python -m examples.replay_bot --source data.json --journal replay_output.jsonl
|
|
16
|
+
|
|
17
|
+
Input Format:
|
|
18
|
+
The source JSON should match the /v1/history/daily response shape:
|
|
19
|
+
{
|
|
20
|
+
"start_date": "2026-03-01",
|
|
21
|
+
"end_date": "2026-03-07",
|
|
22
|
+
"rows": [
|
|
23
|
+
{
|
|
24
|
+
"date": "2026-03-01",
|
|
25
|
+
"conditions_state": { "gate": "open", "direction": "long", ... },
|
|
26
|
+
"gate_state": { "state": "open", "max_position_scale": 1.0, ... },
|
|
27
|
+
"posture_state": { "posture_state": "risk-on", "posture_score": 0.78, ... }
|
|
28
|
+
},
|
|
29
|
+
...
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Output:
|
|
34
|
+
- JSONL replay journal (default: output/replay_journal_{date}.jsonl)
|
|
35
|
+
- Per-step summary printed to stderr
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
from __future__ import annotations
|
|
39
|
+
|
|
40
|
+
import argparse
|
|
41
|
+
import json
|
|
42
|
+
import os
|
|
43
|
+
import sys
|
|
44
|
+
from datetime import datetime, timezone
|
|
45
|
+
from pathlib import Path
|
|
46
|
+
|
|
47
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
48
|
+
|
|
49
|
+
from marketschema import MarketSchemaClient
|
|
50
|
+
from marketschema.paper_bot import PaperBotRunner
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def fetch_history(api_key: str, base_url: str, start: str, end: str, output: str) -> str:
|
|
54
|
+
"""Fetch history/daily from the API and save to a local file.
|
|
55
|
+
|
|
56
|
+
NOTE: SDK v1.0.0 does not include history_daily() endpoint.
|
|
57
|
+
The --fetch option is no longer supported. Use --source to provide a pre-exported JSON file.
|
|
58
|
+
"""
|
|
59
|
+
print("ERROR: --fetch is not supported in SDK v1.0.0", file=sys.stderr)
|
|
60
|
+
print(" The history_daily() method was removed from the public API.", file=sys.stderr)
|
|
61
|
+
print(" Use --source <path> to replay from a pre-exported JSON file instead.", file=sys.stderr)
|
|
62
|
+
raise RuntimeError("fetch_history not supported in v1.0.0")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def main() -> None:
|
|
66
|
+
parser = argparse.ArgumentParser(
|
|
67
|
+
description="MarketSchema Replay Bot — historical state replay"
|
|
68
|
+
)
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"--source",
|
|
71
|
+
default=None,
|
|
72
|
+
help="Path to a history/daily JSON export file",
|
|
73
|
+
)
|
|
74
|
+
parser.add_argument(
|
|
75
|
+
"--fetch",
|
|
76
|
+
action="store_true",
|
|
77
|
+
help="Fetch history from the API first (requires MS_API_KEY)",
|
|
78
|
+
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"--start",
|
|
81
|
+
default=None,
|
|
82
|
+
help="Start date for --fetch (YYYY-MM-DD)",
|
|
83
|
+
)
|
|
84
|
+
parser.add_argument(
|
|
85
|
+
"--end",
|
|
86
|
+
default=None,
|
|
87
|
+
help="End date for --fetch (YYYY-MM-DD)",
|
|
88
|
+
)
|
|
89
|
+
parser.add_argument(
|
|
90
|
+
"--journal",
|
|
91
|
+
default=None,
|
|
92
|
+
help="Journal output path (default: output/replay_journal_{date}.jsonl)",
|
|
93
|
+
)
|
|
94
|
+
args = parser.parse_args()
|
|
95
|
+
|
|
96
|
+
# Determine source
|
|
97
|
+
source_path = args.source
|
|
98
|
+
if args.fetch:
|
|
99
|
+
api_key = os.environ.get("MS_API_KEY")
|
|
100
|
+
if not api_key:
|
|
101
|
+
print("ERROR: MS_API_KEY required for --fetch", file=sys.stderr)
|
|
102
|
+
sys.exit(1)
|
|
103
|
+
if not args.start or not args.end:
|
|
104
|
+
print("ERROR: --start and --end required for --fetch", file=sys.stderr)
|
|
105
|
+
sys.exit(1)
|
|
106
|
+
base_url = os.environ.get("MS_BASE_URL", "https://api.marketschema.com")
|
|
107
|
+
source_path = fetch_history(
|
|
108
|
+
api_key, base_url, args.start, args.end,
|
|
109
|
+
output=f"output/history_{args.start}_{args.end}.json",
|
|
110
|
+
)
|
|
111
|
+
elif not source_path:
|
|
112
|
+
print("ERROR: Provide --source <path> or --fetch --start ... --end ...", file=sys.stderr)
|
|
113
|
+
sys.exit(1)
|
|
114
|
+
|
|
115
|
+
# Default journal path
|
|
116
|
+
journal_path = args.journal
|
|
117
|
+
if not journal_path:
|
|
118
|
+
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
119
|
+
journal_path = f"output/replay_journal_{today}.jsonl"
|
|
120
|
+
|
|
121
|
+
print(f"Replay Bot starting:", file=sys.stderr)
|
|
122
|
+
print(f" Source: {source_path}", file=sys.stderr)
|
|
123
|
+
print(f" Journal: {journal_path}", file=sys.stderr)
|
|
124
|
+
print(f" Mode: REPLAY (historical, no API calls)", file=sys.stderr)
|
|
125
|
+
print(file=sys.stderr)
|
|
126
|
+
|
|
127
|
+
runner = PaperBotRunner.from_replay(
|
|
128
|
+
source=source_path,
|
|
129
|
+
journal_path=journal_path,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
summary = runner.run()
|
|
133
|
+
|
|
134
|
+
print(file=sys.stderr)
|
|
135
|
+
print(
|
|
136
|
+
f"Replay complete. {summary['cycles_completed']} steps logged to {journal_path}",
|
|
137
|
+
file=sys.stderr,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
if __name__ == "__main__":
|
|
142
|
+
main()
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""MarketSchema Shadow Bot — Non-Executing Observation Mode
|
|
3
|
+
|
|
4
|
+
Shadow mode runs the same decision logic as a live paper-trading bot,
|
|
5
|
+
but does NOT execute any trades. All decisions are logged for later
|
|
6
|
+
comparison against actual live executions, validating signal consistency.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
# Set your API key
|
|
10
|
+
export MS_API_KEY="ms_live_..."
|
|
11
|
+
|
|
12
|
+
# Run 10 cycles at 60-second intervals (default)
|
|
13
|
+
python -m examples.shadow_bot
|
|
14
|
+
|
|
15
|
+
# Custom watchlist and cycle count
|
|
16
|
+
python -m examples.shadow_bot --watchlist AAPL,MSFT,NVDA,TSLA --cycles 20 --interval 30
|
|
17
|
+
|
|
18
|
+
# With custom journal output
|
|
19
|
+
python -m examples.shadow_bot --journal shadow_decisions.jsonl
|
|
20
|
+
|
|
21
|
+
Environment Variables:
|
|
22
|
+
MS_API_KEY Required. Your MarketSchema API key.
|
|
23
|
+
MS_BASE_URL Optional. API base URL (default: https://api.marketschema.com).
|
|
24
|
+
|
|
25
|
+
Output:
|
|
26
|
+
- JSONL decision journal (default: output/shadow_journal_{date}.jsonl)
|
|
27
|
+
- Summary printed to stderr after completion
|
|
28
|
+
- All journal entries marked with mode="shadow" and execution="withheld"
|
|
29
|
+
|
|
30
|
+
Usage Patterns:
|
|
31
|
+
1. Run shadow_bot in parallel with live trading to compare decisions
|
|
32
|
+
2. Backtest shadow journals against historical data for validation
|
|
33
|
+
3. Use to validate signal consistency before production deployment
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
|
|
38
|
+
import argparse
|
|
39
|
+
import os
|
|
40
|
+
import sys
|
|
41
|
+
from datetime import datetime, timezone
|
|
42
|
+
|
|
43
|
+
# Allow running from sdk/python/ or repo root
|
|
44
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
45
|
+
|
|
46
|
+
from marketschema import MarketSchemaClient
|
|
47
|
+
from marketschema.paper_bot import PaperBotRunner
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def main() -> None:
|
|
51
|
+
parser = argparse.ArgumentParser(
|
|
52
|
+
description="MarketSchema Shadow Bot — non-executing observation mode"
|
|
53
|
+
)
|
|
54
|
+
parser.add_argument(
|
|
55
|
+
"--watchlist",
|
|
56
|
+
default="SPY,QQQ,AAPL,MSFT,NVDA",
|
|
57
|
+
help="Comma-separated ticker watchlist (default: SPY,QQQ,AAPL,MSFT,NVDA)",
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"--cycles",
|
|
61
|
+
type=int,
|
|
62
|
+
default=10,
|
|
63
|
+
help="Number of polling cycles (default: 10)",
|
|
64
|
+
)
|
|
65
|
+
parser.add_argument(
|
|
66
|
+
"--interval",
|
|
67
|
+
type=int,
|
|
68
|
+
default=60,
|
|
69
|
+
help="Seconds between polls (default: 60)",
|
|
70
|
+
)
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"--horizon",
|
|
73
|
+
default="swing",
|
|
74
|
+
choices=["day", "swing", "position"],
|
|
75
|
+
help="Trading horizon for batch checks (default: swing)",
|
|
76
|
+
)
|
|
77
|
+
parser.add_argument(
|
|
78
|
+
"--style",
|
|
79
|
+
default=None,
|
|
80
|
+
help="Trading style for batch checks (e.g., momentum, mean_reversion)",
|
|
81
|
+
)
|
|
82
|
+
parser.add_argument(
|
|
83
|
+
"--journal",
|
|
84
|
+
default=None,
|
|
85
|
+
help="Journal output path (default: output/shadow_journal_{date}.jsonl)",
|
|
86
|
+
)
|
|
87
|
+
parser.add_argument(
|
|
88
|
+
"--bot-name",
|
|
89
|
+
default="ms-shadow-bot",
|
|
90
|
+
help="Bot registration name (default: ms-shadow-bot)",
|
|
91
|
+
)
|
|
92
|
+
parser.add_argument(
|
|
93
|
+
"--strategy-label",
|
|
94
|
+
default=None,
|
|
95
|
+
help="Strategy label for bot registration",
|
|
96
|
+
)
|
|
97
|
+
args = parser.parse_args()
|
|
98
|
+
|
|
99
|
+
# Validate API key
|
|
100
|
+
api_key = os.environ.get("MS_API_KEY")
|
|
101
|
+
if not api_key:
|
|
102
|
+
print("ERROR: MS_API_KEY environment variable is required.", file=sys.stderr)
|
|
103
|
+
print(" export MS_API_KEY='ms_live_...'", file=sys.stderr)
|
|
104
|
+
sys.exit(1)
|
|
105
|
+
|
|
106
|
+
base_url = os.environ.get("MS_BASE_URL", "https://api.marketschema.com")
|
|
107
|
+
|
|
108
|
+
# Default journal path
|
|
109
|
+
journal_path = args.journal
|
|
110
|
+
if not journal_path:
|
|
111
|
+
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
112
|
+
journal_path = f"output/shadow_journal_{today}.jsonl"
|
|
113
|
+
|
|
114
|
+
# Build client and runner
|
|
115
|
+
client = MarketSchemaClient(api_key=api_key, base_url=base_url)
|
|
116
|
+
watchlist = [t.strip() for t in args.watchlist.split(",")]
|
|
117
|
+
|
|
118
|
+
runner = PaperBotRunner.from_client(
|
|
119
|
+
client=client,
|
|
120
|
+
watchlist=watchlist,
|
|
121
|
+
horizon=args.horizon,
|
|
122
|
+
style=args.style,
|
|
123
|
+
journal_path=journal_path,
|
|
124
|
+
bot_name=args.bot_name,
|
|
125
|
+
strategy_label=args.strategy_label,
|
|
126
|
+
environment="shadow", # Shadow mode!
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
print(f"Shadow Bot starting:", file=sys.stderr)
|
|
130
|
+
print(f" Watchlist: {watchlist}", file=sys.stderr)
|
|
131
|
+
print(f" Cycles: {args.cycles}", file=sys.stderr)
|
|
132
|
+
print(f" Interval: {args.interval}s", file=sys.stderr)
|
|
133
|
+
print(f" Journal: {journal_path}", file=sys.stderr)
|
|
134
|
+
print(f" Mode: SHADOW (observation only, no broker execution)", file=sys.stderr)
|
|
135
|
+
print(file=sys.stderr)
|
|
136
|
+
|
|
137
|
+
summary = runner.run(cycles=args.cycles, interval=args.interval)
|
|
138
|
+
|
|
139
|
+
print(file=sys.stderr)
|
|
140
|
+
print(f"Shadow run complete. {summary['cycles_completed']} cycles logged to {journal_path}", file=sys.stderr)
|
|
141
|
+
if summary.get("setup_report_path"):
|
|
142
|
+
print(f"Setup report: {summary['setup_report_path']}", file=sys.stderr)
|
|
143
|
+
print(file=sys.stderr)
|
|
144
|
+
print("Next steps:", file=sys.stderr)
|
|
145
|
+
print(f" 1. Compare this shadow journal with live trading journal:", file=sys.stderr)
|
|
146
|
+
print(f" python -c \"from marketschema.paper_bot import compare_journals; ", file=sys.stderr)
|
|
147
|
+
print(f" print(compare_journals('{journal_path}', 'live_journal.jsonl'))\"", file=sys.stderr)
|
|
148
|
+
print(f" 2. Analyze decision consistency and signal quality", file=sys.stderr)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if __name__ == "__main__":
|
|
152
|
+
main()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""MarketSchema Python SDK v1.0.0 — Public API Client
|
|
2
|
+
|
|
3
|
+
Lightweight, zero-dependency (beyond requests) client for the
|
|
4
|
+
MarketSchema Public API v1. Provides access to 10 PUBLIC_KEEP endpoints:
|
|
5
|
+
- Auth: whoami, capabilities, stream-token
|
|
6
|
+
- Asset Packets: asset, batch
|
|
7
|
+
- Delivery: stream, webhook_register, webhook_list, webhook_delete, webhook_test
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
from marketschema import MarketSchemaClient
|
|
11
|
+
|
|
12
|
+
client = MarketSchemaClient(api_key="ms_...")
|
|
13
|
+
|
|
14
|
+
# Verify identity
|
|
15
|
+
identity = client.whoami()
|
|
16
|
+
print(f"Plan: {identity['plan']}")
|
|
17
|
+
|
|
18
|
+
# Get schema score for a ticker
|
|
19
|
+
score = client.asset("AAPL")
|
|
20
|
+
print(f"AAPL schema score: {score['schema_score']['score']}")
|
|
21
|
+
|
|
22
|
+
# Batch check multiple tickers
|
|
23
|
+
batch = client.batch(tickers=["MSFT", "GOOGL", "TSLA"])
|
|
24
|
+
|
|
25
|
+
# Register webhook for score changes
|
|
26
|
+
webhook = client.webhook_register("https://example.com/webhook")
|
|
27
|
+
|
|
28
|
+
# Stream live updates
|
|
29
|
+
for event in client.stream():
|
|
30
|
+
print(event)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from marketschema.client import MarketSchemaClient
|
|
34
|
+
|
|
35
|
+
__version__ = "1.1.0"
|
|
36
|
+
__all__ = ["MarketSchemaClient"]
|