melaya 0.1.2 → 0.2.0

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.
@@ -1,155 +1,170 @@
1
- # frozen_string_literal: true
2
-
3
- module Melaya
4
- # Strategies API — launch, control, and inspect trading strategies.
5
- #
6
- # A strategy is a server-managed runner (the Trading Engine, or an Agentic
7
- # Trading Crew) that trades a universe on a cadence with server-side SL/TP
8
- # and safety rails. Launch in paper mode (dry_run: true) or live
9
- # (dry_run: false, which requires a connected exchange key).
10
- #
11
- # Maps to https://api.melaya.org/api/v1/strategies/* on the private plane.
12
- class StrategiesAPI
13
- def initialize(http)
14
- @http = http
15
- end
16
-
17
- # Every strategy you own (running, paused, paper, and live).
18
- def list
19
- @http.get("/api/v1/strategies/list")["strategies"]
20
- end
21
-
22
- # A single strategy by id.
23
- # @param strategy_id [String]
24
- def get(strategy_id)
25
- @http.get("/api/v1/strategies/#{strategy_id}")["strategy"]
26
- end
27
-
28
- # Launch a strategy. Pass dry_run: true for paper; live needs api_key_id.
29
- # Returns the full response hash (includes "strategyId").
30
- #
31
- # @param name [String]
32
- # @param strategy_type [String] e.g. "custom"
33
- # @param exchange [String]
34
- # @param market [String, nil]
35
- # @param symbol [String, nil]
36
- # @param api_key_id [String, nil]
37
- # @param params [Hash, nil]
38
- # @param runtime_mode [String, nil]
39
- # @param dry_run [Boolean]
40
- # @param key_bindings [Hash, nil]
41
- def create(name:, strategy_type:, exchange:, market: nil, symbol: nil,
42
- api_key_id: nil, params: nil, runtime_mode: nil, dry_run: true,
43
- key_bindings: nil)
44
- body = {
45
- "name" => name,
46
- "strategyType" => strategy_type,
47
- "exchange" => exchange,
48
- "market" => market,
49
- "symbol" => symbol,
50
- "apiKeyId" => api_key_id,
51
- "params" => params,
52
- "runtimeMode" => runtime_mode,
53
- "dryRun" => dry_run,
54
- "keyBindings" => key_bindings,
55
- }.reject { |_, v| v.nil? }
56
- @http.post("/api/v1/strategies", body)
57
- end
58
-
59
- # Pause a running strategy (stops entering new cycles until resumed).
60
- def pause(strategy_id)
61
- @http.post("/api/v1/strategies/#{strategy_id}/pause")
62
- end
63
-
64
- # Resume a paused strategy.
65
- def resume(strategy_id)
66
- @http.post("/api/v1/strategies/#{strategy_id}/resume")
67
- end
68
-
69
- # Stop a strategy and tear down its runner. Cancels any in-flight approvals.
70
- def stop(strategy_id)
71
- @http.post("/api/v1/strategies/#{strategy_id}/stop")
72
- end
73
-
74
- # Soft-delete a strategy.
75
- def delete(strategy_id)
76
- @http.delete("/api/v1/strategies/#{strategy_id}")
77
- end
78
-
79
- # Update a running strategy's params (e.g. universe, cadence, risk caps).
80
- # @param strategy_id [String]
81
- # @param params [Hash]
82
- def update_params(strategy_id, params)
83
- @http.post("/api/v1/strategies/#{strategy_id}/update-params", params)
84
- end
85
-
86
- # Live runtime status of a strategy's runner (container health, tick count).
87
- def status(strategy_id)
88
- @http.get("/api/v1/strategies/#{strategy_id}/status")
89
- end
90
-
91
- # Performance series for a strategy (equity, PnL over time).
92
- def performance(strategy_id)
93
- @http.get("/api/v1/strategies/#{strategy_id}/performance")["rows"]
94
- end
95
-
96
- # Execution (order) rows for a strategy.
97
- def executions(strategy_id)
98
- @http.get("/api/v1/strategies/#{strategy_id}/executions")["rows"]
99
- end
100
-
101
- # Trade (fill) rows for a strategy.
102
- def trades(strategy_id)
103
- @http.get("/api/v1/strategies/#{strategy_id}/trades")["rows"]
104
- end
105
-
106
- # Log rows for a strategy (cycle markers, persona messages, errors).
107
- def logs(strategy_id)
108
- @http.get("/api/v1/strategies/#{strategy_id}/logs")["rows"]
109
- end
110
-
111
- # ── AI parameter optimizer ────────────────────────────────────────────────
112
-
113
- # Kick off an AI-driven parameter optimization.
114
- # +param_bounds+ maps each param name to a [min, max] array.
115
- # +objective+ defaults to "sharpe"; +max_iterations+ is clamped to 1-20.
116
- # Returns a hash including "runId".
117
- #
118
- # @param strategy_id [String]
119
- # @param param_bounds [Hash] e.g. { "qty" => [0.001, 0.1] }
120
- # @param objective [String]
121
- # @param max_iterations [Integer]
122
- # @param require_approval [Boolean, nil]
123
- def ai_opt_start(strategy_id, param_bounds:, objective: "sharpe",
124
- max_iterations: 3, require_approval: nil)
125
- body = {
126
- "paramBounds" => param_bounds,
127
- "objective" => objective,
128
- "maxIterations" => max_iterations,
129
- }
130
- body["requireApproval"] = require_approval unless require_approval.nil?
131
- @http.post("/api/v1/strategies/#{strategy_id}/ai-opt/start", body)
132
- end
133
-
134
- # Current optimization status for a strategy.
135
- def ai_opt_status(strategy_id)
136
- @http.get("/api/v1/strategies/#{strategy_id}/ai-opt/status")
137
- end
138
-
139
- # Approve and apply the optimizer's proposed params to the running strategy.
140
- # @param body [Hash] optional extra params
141
- def ai_opt_approve(strategy_id, body = {})
142
- @http.post("/api/v1/strategies/#{strategy_id}/ai-opt/approve", body)
143
- end
144
-
145
- # Stop an in-progress optimization.
146
- def ai_opt_stop(strategy_id)
147
- @http.post("/api/v1/strategies/#{strategy_id}/ai-opt/stop")
148
- end
149
-
150
- # Past optimization runs for a strategy.
151
- def ai_opt_runs(strategy_id)
152
- @http.get("/api/v1/strategies/#{strategy_id}/ai-opt/runs")
153
- end
154
- end
155
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Melaya
4
+ # Strategies API — launch, control, and inspect trading strategies.
5
+ #
6
+ # A strategy is a server-managed runner (the Trading Engine, or an Agentic
7
+ # Trading Crew) that trades a universe on a cadence with server-side SL/TP
8
+ # and safety rails. Launch in paper mode (dry_run: true) or live
9
+ # (dry_run: false, which requires a connected exchange key).
10
+ #
11
+ # Maps to https://api.melaya.org/api/v1/strategies/* on the private plane.
12
+ class StrategiesAPI
13
+ def initialize(http)
14
+ @http = http
15
+ end
16
+
17
+ # Every strategy you own (running, paused, paper, and live).
18
+ def list
19
+ @http.get("/api/v1/strategies/list")["strategies"]
20
+ end
21
+
22
+ # A single strategy by id.
23
+ # @param strategy_id [String]
24
+ def get(strategy_id)
25
+ @http.get("/api/v1/strategies/#{strategy_id}")["strategy"]
26
+ end
27
+
28
+ # Launch a strategy. Pass dry_run: true for paper; live needs api_key_id.
29
+ # Returns the full response hash (includes "strategyId").
30
+ #
31
+ # @param name [String]
32
+ # @param strategy_type [String] e.g. "custom"
33
+ # @param exchange [String]
34
+ # @param market [String, nil]
35
+ # @param symbol [String, nil]
36
+ # @param api_key_id [String, nil]
37
+ # @param params [Hash, nil]
38
+ # @param runtime_mode [String, nil]
39
+ # @param dry_run [Boolean]
40
+ # @param key_bindings [Hash, nil]
41
+ def create(name:, strategy_type:, exchange:, market: nil, symbol: nil,
42
+ api_key_id: nil, params: nil, runtime_mode: nil, dry_run: true,
43
+ key_bindings: nil)
44
+ body = {
45
+ "name" => name,
46
+ "strategyType" => strategy_type,
47
+ "exchange" => exchange,
48
+ "market" => market,
49
+ "symbol" => symbol,
50
+ "apiKeyId" => api_key_id,
51
+ "params" => params,
52
+ "runtimeMode" => runtime_mode,
53
+ "dryRun" => dry_run,
54
+ "keyBindings" => key_bindings,
55
+ }.reject { |_, v| v.nil? }
56
+ @http.post("/api/v1/strategies", body)
57
+ end
58
+
59
+ # Pause a running strategy (stops entering new cycles until resumed).
60
+ def pause(strategy_id)
61
+ @http.post("/api/v1/strategies/#{strategy_id}/pause")
62
+ end
63
+
64
+ # Resume a paused strategy.
65
+ def resume(strategy_id)
66
+ @http.post("/api/v1/strategies/#{strategy_id}/resume")
67
+ end
68
+
69
+ # Stop a strategy and tear down its runner. Cancels any in-flight approvals.
70
+ def stop(strategy_id)
71
+ @http.post("/api/v1/strategies/#{strategy_id}/stop")
72
+ end
73
+
74
+ # Soft-delete a strategy.
75
+ def delete(strategy_id)
76
+ @http.delete("/api/v1/strategies/#{strategy_id}")
77
+ end
78
+
79
+ # Update a running strategy's params (e.g. universe, cadence, risk caps).
80
+ # @param strategy_id [String]
81
+ # @param params [Hash]
82
+ def update_params(strategy_id, params)
83
+ @http.post("/api/v1/strategies/#{strategy_id}/update-params", params)
84
+ end
85
+
86
+ # Live runtime status of a strategy's runner (container health, tick count).
87
+ def status(strategy_id)
88
+ @http.get("/api/v1/strategies/#{strategy_id}/status")
89
+ end
90
+
91
+ # Performance series for a strategy (equity, PnL over time).
92
+ def performance(strategy_id)
93
+ @http.get("/api/v1/strategies/#{strategy_id}/performance")["rows"]
94
+ end
95
+
96
+ # Execution (order) rows for a strategy.
97
+ def executions(strategy_id)
98
+ @http.get("/api/v1/strategies/#{strategy_id}/executions")["rows"]
99
+ end
100
+
101
+ # Trade (fill) rows for a strategy.
102
+ def trades(strategy_id)
103
+ @http.get("/api/v1/strategies/#{strategy_id}/trades")["rows"]
104
+ end
105
+
106
+ # Log rows for a strategy (cycle markers, persona messages, errors).
107
+ def logs(strategy_id)
108
+ @http.get("/api/v1/strategies/#{strategy_id}/logs")["rows"]
109
+ end
110
+
111
+ # ── AI parameter optimizer ────────────────────────────────────────────────
112
+
113
+ # Kick off an AI-driven parameter optimization.
114
+ # +param_bounds+ maps each param name to a [min, max] array.
115
+ # +objective+ defaults to "sharpe"; +max_iterations+ is clamped to 1-20.
116
+ # Returns a hash including "runId".
117
+ #
118
+ # @param strategy_id [String]
119
+ # @param param_bounds [Hash] e.g. { "qty" => [0.001, 0.1] }
120
+ # @param objective [String]
121
+ # @param max_iterations [Integer]
122
+ # @param require_approval [Boolean, nil]
123
+ def ai_opt_start(strategy_id, param_bounds:, objective: "sharpe",
124
+ max_iterations: 3, require_approval: nil)
125
+ body = {
126
+ "paramBounds" => param_bounds,
127
+ "objective" => objective,
128
+ "maxIterations" => max_iterations,
129
+ }
130
+ body["requireApproval"] = require_approval unless require_approval.nil?
131
+ @http.post("/api/v1/strategies/#{strategy_id}/ai-opt/start", body)
132
+ end
133
+
134
+ # Current optimization status for a strategy.
135
+ def ai_opt_status(strategy_id)
136
+ @http.get("/api/v1/strategies/#{strategy_id}/ai-opt/status")
137
+ end
138
+
139
+ # Approve and apply the optimizer's proposed params to the running strategy.
140
+ # @param body [Hash] optional extra params
141
+ def ai_opt_approve(strategy_id, body = {})
142
+ @http.post("/api/v1/strategies/#{strategy_id}/ai-opt/approve", body)
143
+ end
144
+
145
+ # Stop an in-progress optimization.
146
+ def ai_opt_stop(strategy_id)
147
+ @http.post("/api/v1/strategies/#{strategy_id}/ai-opt/stop")
148
+ end
149
+
150
+ # Past optimization runs for a strategy.
151
+ def ai_opt_runs(strategy_id)
152
+ @http.get("/api/v1/strategies/#{strategy_id}/ai-opt/runs")
153
+ end
154
+
155
+ # ── restRoutes.ts strategies endpoints ────────────────────────────────────
156
+
157
+ # GET /api/v1/private/strategies/team
158
+ # List strategies visible to the caller's team project.
159
+ def list_team
160
+ @http.get("/api/v1/private/strategies/team")
161
+ end
162
+
163
+ # POST /api/v1/private/strategies/summaries/bulk
164
+ # Bulk-fetch lightweight summaries for a list of strategy IDs.
165
+ # @param strategy_ids [Array<String>]
166
+ def summaries_bulk(strategy_ids)
167
+ @http.post("/api/v1/private/strategies/summaries/bulk", "strategyIds" => strategy_ids)
168
+ end
169
+ end
170
+ end