melaya 0.1.2 → 0.1.4
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.
- checksums.yaml +4 -4
- data/README.md +163 -163
- data/lib/melaya/account.rb +30 -30
- data/lib/melaya/backtest.rb +101 -101
- data/lib/melaya/errors.rb +15 -15
- data/lib/melaya/http_client.rb +97 -97
- data/lib/melaya/market.rb +156 -156
- data/lib/melaya/sim.rb +110 -110
- data/lib/melaya/strategies.rb +155 -155
- data/lib/melaya/stream.rb +336 -336
- data/lib/melaya/trade.rb +168 -168
- data/lib/melaya/version.rb +1 -1
- data/lib/melaya.rb +79 -79
- data/melaya.gemspec +23 -23
- metadata +6 -3
data/lib/melaya/trade.rb
CHANGED
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Melaya
|
|
4
|
-
# Live trading API — credentialed order placement, account state, and
|
|
5
|
-
# position management on a CONNECTED exchange.
|
|
6
|
-
#
|
|
7
|
-
# Every method POSTs to +https://api.melaya.org/api/v1/private/<op>+; the server
|
|
8
|
-
# resolves your connected exchange credential (referenced by +api_key_id+ — see
|
|
9
|
-
# AccountAPI#keys) and forwards the call to the venue through Melaya's in-house
|
|
10
|
-
# Rust engine. Responses share an envelope:
|
|
11
|
-
# +{ ok, exchange, operation, orderId, clientOrderId, payload, data, ... }+.
|
|
12
|
-
#
|
|
13
|
-
# WARNING: these hit the REAL venue with REAL funds. The write methods
|
|
14
|
-
# (create_order, cancel_order, amend_order, cancel_all_orders, cancel_plan_orders,
|
|
15
|
-
# close_position, set_leverage, set_margin_mode, set_position_mode) move money or
|
|
16
|
-
# change account state. For risk-free testing use the sim (paper) broker or a
|
|
17
|
-
# paper strategy instead.
|
|
18
|
-
class TradeAPI
|
|
19
|
-
def initialize(http)
|
|
20
|
-
@http = http
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# ── Account state (reads) ──────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
# Live account balance on a connected venue.
|
|
26
|
-
def balance(exchange:, api_key_id: nil, key_id: nil, market_type: nil, params: nil)
|
|
27
|
-
op("balance", exchange: exchange, apiKeyId: api_key_id, keyId: key_id,
|
|
28
|
-
marketType: market_type, params: params)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Live open positions.
|
|
32
|
-
def positions(exchange:, api_key_id: nil, market_type: nil, symbol: nil, params: nil)
|
|
33
|
-
op("positions", exchange: exchange, apiKeyId: api_key_id,
|
|
34
|
-
marketType: market_type, symbol: symbol, params: params)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Historical positions (venue-dependent).
|
|
38
|
-
def positions_history(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
39
|
-
op("positions-history", exchange: exchange, apiKeyId: api_key_id,
|
|
40
|
-
marketType: market_type, symbol: symbol)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Resting (open) orders.
|
|
44
|
-
def open_orders(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
45
|
-
op("open-orders", exchange: exchange, apiKeyId: api_key_id,
|
|
46
|
-
marketType: market_type, symbol: symbol)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# All orders (open + recent).
|
|
50
|
-
def orders(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
51
|
-
op("orders", exchange: exchange, apiKeyId: api_key_id,
|
|
52
|
-
marketType: market_type, symbol: symbol)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Closed/filled orders.
|
|
56
|
-
def closed_orders(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
57
|
-
op("closed-orders", exchange: exchange, apiKeyId: api_key_id,
|
|
58
|
-
marketType: market_type, symbol: symbol)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Your trade (fill) history.
|
|
62
|
-
def my_trades(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
63
|
-
op("my-trades", exchange: exchange, apiKeyId: api_key_id,
|
|
64
|
-
marketType: market_type, symbol: symbol)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Extended trade history (venue-dependent).
|
|
68
|
-
def my_trades_history(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
69
|
-
op("my-trades-history", exchange: exchange, apiKeyId: api_key_id,
|
|
70
|
-
marketType: market_type, symbol: symbol)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Resting conditional/plan (trigger) orders.
|
|
74
|
-
def plan_orders(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
75
|
-
op("plan-orders", exchange: exchange, apiKeyId: api_key_id,
|
|
76
|
-
marketType: market_type, symbol: symbol)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# Current leverage for a symbol.
|
|
80
|
-
def leverage(exchange:, api_key_id: nil, symbol: nil, market_type: nil)
|
|
81
|
-
op("leverage", exchange: exchange, apiKeyId: api_key_id,
|
|
82
|
-
symbol: symbol, marketType: market_type)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Leverage tiers / brackets for a symbol.
|
|
86
|
-
def leverage_tiers(exchange:, api_key_id: nil, symbol: nil, market_type: nil)
|
|
87
|
-
op("leverage-tiers", exchange: exchange, apiKeyId: api_key_id,
|
|
88
|
-
symbol: symbol, marketType: market_type)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# ── Order placement & management (LIVE writes — real funds) ───────────────
|
|
92
|
-
|
|
93
|
-
# Place a live order on the venue. WARNING: real money.
|
|
94
|
-
# stop_price, take_profit_price, and reduce_only are folded into +params+.
|
|
95
|
-
def create_order(exchange:, symbol:, side:, amount:,
|
|
96
|
-
api_key_id: nil, type: "market", price: nil,
|
|
97
|
-
market_type: nil, stop_price: nil, take_profit_price: nil,
|
|
98
|
-
reduce_only: nil, leverage: nil, client_order_id: nil, params: nil)
|
|
99
|
-
p = (params || {}).dup
|
|
100
|
-
p["stopPrice"] = stop_price unless stop_price.nil?
|
|
101
|
-
p["takeProfitPrice"] = take_profit_price unless take_profit_price.nil?
|
|
102
|
-
p["reduceOnly"] = reduce_only unless reduce_only.nil?
|
|
103
|
-
op("create-order",
|
|
104
|
-
exchange: exchange, apiKeyId: api_key_id, symbol: symbol,
|
|
105
|
-
side: side, amount: amount, type: type, price: price,
|
|
106
|
-
marketType: market_type, leverage: leverage,
|
|
107
|
-
clientOrderId: client_order_id, params: p.empty? ? nil : p)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
# Cancel a live order by id. WARNING.
|
|
111
|
-
def cancel_order(exchange:, api_key_id: nil, order_id: nil, client_order_id: nil,
|
|
112
|
-
symbol: nil, market_type: nil)
|
|
113
|
-
op("cancel-order", exchange: exchange, apiKeyId: api_key_id,
|
|
114
|
-
orderId: order_id, clientOrderId: client_order_id,
|
|
115
|
-
symbol: symbol, marketType: market_type)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# Amend (modify) a live order. WARNING.
|
|
119
|
-
def amend_order(exchange:, api_key_id: nil, order_id: nil, symbol: nil,
|
|
120
|
-
amount: nil, price: nil)
|
|
121
|
-
op("amend-order", exchange: exchange, apiKeyId: api_key_id,
|
|
122
|
-
orderId: order_id, symbol: symbol, amount: amount, price: price)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# Cancel every open order (optionally scoped to a symbol). WARNING.
|
|
126
|
-
def cancel_all_orders(exchange:, api_key_id: nil, symbol: nil, market_type: nil)
|
|
127
|
-
op("cancel-all-orders", exchange: exchange, apiKeyId: api_key_id,
|
|
128
|
-
symbol: symbol, marketType: market_type)
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
# Cancel resting plan/trigger orders. WARNING.
|
|
132
|
-
def cancel_plan_orders(exchange:, api_key_id: nil, symbol: nil, market_type: nil)
|
|
133
|
-
op("cancel-plan-orders", exchange: exchange, apiKeyId: api_key_id,
|
|
134
|
-
symbol: symbol, marketType: market_type)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# Close an open position (market reduce-only). WARNING.
|
|
138
|
-
def close_position(exchange:, symbol:, api_key_id: nil, market_type: nil)
|
|
139
|
-
op("close-position", exchange: exchange, apiKeyId: api_key_id,
|
|
140
|
-
symbol: symbol, marketType: market_type)
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
# Set leverage for a symbol. WARNING.
|
|
144
|
-
def set_leverage(exchange:, symbol:, leverage:, api_key_id: nil, market_type: nil)
|
|
145
|
-
op("set-leverage", exchange: exchange, apiKeyId: api_key_id,
|
|
146
|
-
symbol: symbol, leverage: leverage, marketType: market_type)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Set margin mode (cross/isolated). WARNING.
|
|
150
|
-
def set_margin_mode(exchange:, margin_mode:, api_key_id: nil, symbol: nil, market_type: nil)
|
|
151
|
-
op("set-margin-mode", exchange: exchange, apiKeyId: api_key_id,
|
|
152
|
-
marginMode: margin_mode, symbol: symbol, marketType: market_type)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
# Set position mode (one-way / hedge). WARNING.
|
|
156
|
-
def set_position_mode(exchange:, api_key_id: nil, hedged: nil, mode: nil, market_type: nil)
|
|
157
|
-
op("set-position-mode", exchange: exchange, apiKeyId: api_key_id,
|
|
158
|
-
hedged: hedged, mode: mode, marketType: market_type)
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
private
|
|
162
|
-
|
|
163
|
-
def op(path_op, **kwargs)
|
|
164
|
-
body = kwargs.reject { |_, v| v.nil? }
|
|
165
|
-
@http.post("/api/v1/private/#{path_op}", body)
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Melaya
|
|
4
|
+
# Live trading API — credentialed order placement, account state, and
|
|
5
|
+
# position management on a CONNECTED exchange.
|
|
6
|
+
#
|
|
7
|
+
# Every method POSTs to +https://api.melaya.org/api/v1/private/<op>+; the server
|
|
8
|
+
# resolves your connected exchange credential (referenced by +api_key_id+ — see
|
|
9
|
+
# AccountAPI#keys) and forwards the call to the venue through Melaya's in-house
|
|
10
|
+
# Rust engine. Responses share an envelope:
|
|
11
|
+
# +{ ok, exchange, operation, orderId, clientOrderId, payload, data, ... }+.
|
|
12
|
+
#
|
|
13
|
+
# WARNING: these hit the REAL venue with REAL funds. The write methods
|
|
14
|
+
# (create_order, cancel_order, amend_order, cancel_all_orders, cancel_plan_orders,
|
|
15
|
+
# close_position, set_leverage, set_margin_mode, set_position_mode) move money or
|
|
16
|
+
# change account state. For risk-free testing use the sim (paper) broker or a
|
|
17
|
+
# paper strategy instead.
|
|
18
|
+
class TradeAPI
|
|
19
|
+
def initialize(http)
|
|
20
|
+
@http = http
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# ── Account state (reads) ──────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
# Live account balance on a connected venue.
|
|
26
|
+
def balance(exchange:, api_key_id: nil, key_id: nil, market_type: nil, params: nil)
|
|
27
|
+
op("balance", exchange: exchange, apiKeyId: api_key_id, keyId: key_id,
|
|
28
|
+
marketType: market_type, params: params)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Live open positions.
|
|
32
|
+
def positions(exchange:, api_key_id: nil, market_type: nil, symbol: nil, params: nil)
|
|
33
|
+
op("positions", exchange: exchange, apiKeyId: api_key_id,
|
|
34
|
+
marketType: market_type, symbol: symbol, params: params)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Historical positions (venue-dependent).
|
|
38
|
+
def positions_history(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
39
|
+
op("positions-history", exchange: exchange, apiKeyId: api_key_id,
|
|
40
|
+
marketType: market_type, symbol: symbol)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Resting (open) orders.
|
|
44
|
+
def open_orders(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
45
|
+
op("open-orders", exchange: exchange, apiKeyId: api_key_id,
|
|
46
|
+
marketType: market_type, symbol: symbol)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# All orders (open + recent).
|
|
50
|
+
def orders(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
51
|
+
op("orders", exchange: exchange, apiKeyId: api_key_id,
|
|
52
|
+
marketType: market_type, symbol: symbol)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Closed/filled orders.
|
|
56
|
+
def closed_orders(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
57
|
+
op("closed-orders", exchange: exchange, apiKeyId: api_key_id,
|
|
58
|
+
marketType: market_type, symbol: symbol)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Your trade (fill) history.
|
|
62
|
+
def my_trades(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
63
|
+
op("my-trades", exchange: exchange, apiKeyId: api_key_id,
|
|
64
|
+
marketType: market_type, symbol: symbol)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Extended trade history (venue-dependent).
|
|
68
|
+
def my_trades_history(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
69
|
+
op("my-trades-history", exchange: exchange, apiKeyId: api_key_id,
|
|
70
|
+
marketType: market_type, symbol: symbol)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Resting conditional/plan (trigger) orders.
|
|
74
|
+
def plan_orders(exchange:, api_key_id: nil, market_type: nil, symbol: nil)
|
|
75
|
+
op("plan-orders", exchange: exchange, apiKeyId: api_key_id,
|
|
76
|
+
marketType: market_type, symbol: symbol)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Current leverage for a symbol.
|
|
80
|
+
def leverage(exchange:, api_key_id: nil, symbol: nil, market_type: nil)
|
|
81
|
+
op("leverage", exchange: exchange, apiKeyId: api_key_id,
|
|
82
|
+
symbol: symbol, marketType: market_type)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Leverage tiers / brackets for a symbol.
|
|
86
|
+
def leverage_tiers(exchange:, api_key_id: nil, symbol: nil, market_type: nil)
|
|
87
|
+
op("leverage-tiers", exchange: exchange, apiKeyId: api_key_id,
|
|
88
|
+
symbol: symbol, marketType: market_type)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# ── Order placement & management (LIVE writes — real funds) ───────────────
|
|
92
|
+
|
|
93
|
+
# Place a live order on the venue. WARNING: real money.
|
|
94
|
+
# stop_price, take_profit_price, and reduce_only are folded into +params+.
|
|
95
|
+
def create_order(exchange:, symbol:, side:, amount:,
|
|
96
|
+
api_key_id: nil, type: "market", price: nil,
|
|
97
|
+
market_type: nil, stop_price: nil, take_profit_price: nil,
|
|
98
|
+
reduce_only: nil, leverage: nil, client_order_id: nil, params: nil)
|
|
99
|
+
p = (params || {}).dup
|
|
100
|
+
p["stopPrice"] = stop_price unless stop_price.nil?
|
|
101
|
+
p["takeProfitPrice"] = take_profit_price unless take_profit_price.nil?
|
|
102
|
+
p["reduceOnly"] = reduce_only unless reduce_only.nil?
|
|
103
|
+
op("create-order",
|
|
104
|
+
exchange: exchange, apiKeyId: api_key_id, symbol: symbol,
|
|
105
|
+
side: side, amount: amount, type: type, price: price,
|
|
106
|
+
marketType: market_type, leverage: leverage,
|
|
107
|
+
clientOrderId: client_order_id, params: p.empty? ? nil : p)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Cancel a live order by id. WARNING.
|
|
111
|
+
def cancel_order(exchange:, api_key_id: nil, order_id: nil, client_order_id: nil,
|
|
112
|
+
symbol: nil, market_type: nil)
|
|
113
|
+
op("cancel-order", exchange: exchange, apiKeyId: api_key_id,
|
|
114
|
+
orderId: order_id, clientOrderId: client_order_id,
|
|
115
|
+
symbol: symbol, marketType: market_type)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Amend (modify) a live order. WARNING.
|
|
119
|
+
def amend_order(exchange:, api_key_id: nil, order_id: nil, symbol: nil,
|
|
120
|
+
amount: nil, price: nil)
|
|
121
|
+
op("amend-order", exchange: exchange, apiKeyId: api_key_id,
|
|
122
|
+
orderId: order_id, symbol: symbol, amount: amount, price: price)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Cancel every open order (optionally scoped to a symbol). WARNING.
|
|
126
|
+
def cancel_all_orders(exchange:, api_key_id: nil, symbol: nil, market_type: nil)
|
|
127
|
+
op("cancel-all-orders", exchange: exchange, apiKeyId: api_key_id,
|
|
128
|
+
symbol: symbol, marketType: market_type)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Cancel resting plan/trigger orders. WARNING.
|
|
132
|
+
def cancel_plan_orders(exchange:, api_key_id: nil, symbol: nil, market_type: nil)
|
|
133
|
+
op("cancel-plan-orders", exchange: exchange, apiKeyId: api_key_id,
|
|
134
|
+
symbol: symbol, marketType: market_type)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Close an open position (market reduce-only). WARNING.
|
|
138
|
+
def close_position(exchange:, symbol:, api_key_id: nil, market_type: nil)
|
|
139
|
+
op("close-position", exchange: exchange, apiKeyId: api_key_id,
|
|
140
|
+
symbol: symbol, marketType: market_type)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Set leverage for a symbol. WARNING.
|
|
144
|
+
def set_leverage(exchange:, symbol:, leverage:, api_key_id: nil, market_type: nil)
|
|
145
|
+
op("set-leverage", exchange: exchange, apiKeyId: api_key_id,
|
|
146
|
+
symbol: symbol, leverage: leverage, marketType: market_type)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Set margin mode (cross/isolated). WARNING.
|
|
150
|
+
def set_margin_mode(exchange:, margin_mode:, api_key_id: nil, symbol: nil, market_type: nil)
|
|
151
|
+
op("set-margin-mode", exchange: exchange, apiKeyId: api_key_id,
|
|
152
|
+
marginMode: margin_mode, symbol: symbol, marketType: market_type)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Set position mode (one-way / hedge). WARNING.
|
|
156
|
+
def set_position_mode(exchange:, api_key_id: nil, hedged: nil, mode: nil, market_type: nil)
|
|
157
|
+
op("set-position-mode", exchange: exchange, apiKeyId: api_key_id,
|
|
158
|
+
hedged: hedged, mode: mode, marketType: market_type)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
private
|
|
162
|
+
|
|
163
|
+
def op(path_op, **kwargs)
|
|
164
|
+
body = kwargs.reject { |_, v| v.nil? }
|
|
165
|
+
@http.post("/api/v1/private/#{path_op}", body)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
data/lib/melaya/version.rb
CHANGED
data/lib/melaya.rb
CHANGED
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "melaya/version"
|
|
4
|
-
require_relative "melaya/errors"
|
|
5
|
-
require_relative "melaya/http_client"
|
|
6
|
-
require_relative "melaya/market"
|
|
7
|
-
require_relative "melaya/account"
|
|
8
|
-
require_relative "melaya/sim"
|
|
9
|
-
require_relative "melaya/strategies"
|
|
10
|
-
require_relative "melaya/backtest"
|
|
11
|
-
require_relative "melaya/stream"
|
|
12
|
-
require_relative "melaya/trade"
|
|
13
|
-
|
|
14
|
-
module Melaya
|
|
15
|
-
# The Melaya client.
|
|
16
|
-
#
|
|
17
|
-
# @example
|
|
18
|
-
# require "melaya"
|
|
19
|
-
# melaya = Melaya::Client.new(api_key: ENV["MK"])
|
|
20
|
-
#
|
|
21
|
-
# # Market data
|
|
22
|
-
# t = melaya.market.ticker(exchange: "binance", symbol: "BTC/USDT", market: "spot")
|
|
23
|
-
# puts t["last"]
|
|
24
|
-
#
|
|
25
|
-
# # Paper strategy
|
|
26
|
-
# result = melaya.strategies.create(
|
|
27
|
-
# name: "my-bot", strategy_type: "custom", exchange: "binanceusdm",
|
|
28
|
-
# symbol: "BTC/USDT:USDT", market: "FUTURES", dry_run: true,
|
|
29
|
-
# params: { language: "rhai", definition: 'fn evaluate() { emit_long(param("qty")); }', qty: 0.001 }
|
|
30
|
-
# )
|
|
31
|
-
# sid = result["strategyId"]
|
|
32
|
-
# melaya.strategies.stop(sid)
|
|
33
|
-
# melaya.strategies.delete(sid)
|
|
34
|
-
class Client
|
|
35
|
-
# REST market-data + reference endpoints (public plane).
|
|
36
|
-
attr_reader :market
|
|
37
|
-
# Authenticated account reads: connected keys, tier limits, usage.
|
|
38
|
-
attr_reader :account
|
|
39
|
-
# Paper trading (sim broker): virtual balance, positions, and orders.
|
|
40
|
-
attr_reader :sim
|
|
41
|
-
# Launch, control, and inspect trading strategies (paper + live).
|
|
42
|
-
attr_reader :strategies
|
|
43
|
-
# Historical backtests + parameter sweeps on the Rust engine.
|
|
44
|
-
attr_reader :backtest
|
|
45
|
-
# WebSocket streaming endpoints (public market data + private feeds).
|
|
46
|
-
attr_reader :stream
|
|
47
|
-
# Live trading — credentialed order placement and account state on a connected exchange. WARNING: real funds.
|
|
48
|
-
attr_reader :trade
|
|
49
|
-
|
|
50
|
-
# @param api_key [String] your Melaya API key, prefixed +mk_+
|
|
51
|
-
# @param base_url [String] override the REST base URL
|
|
52
|
-
# @param ws_url [String] override the WebSocket base URL
|
|
53
|
-
# @param verify_ssl [Boolean] set false to skip TLS verification (dev-box only).
|
|
54
|
-
# Prefer using ENV["MELAYA_INSECURE_TLS"]="1" rather than passing this directly.
|
|
55
|
-
def initialize(api_key:, base_url: HttpClient::DEFAULT_BASE_URL,
|
|
56
|
-
ws_url: StreamAPI::DEFAULT_WS_URL, verify_ssl: nil)
|
|
57
|
-
raise ArgumentError, "Melaya: api_key is required (create one at melaya.org -> Settings -> API Keys)." \
|
|
58
|
-
if api_key.nil? || api_key.empty?
|
|
59
|
-
raise ArgumentError, "Melaya: API keys must be prefixed 'mk_'." \
|
|
60
|
-
unless api_key.start_with?("mk_")
|
|
61
|
-
|
|
62
|
-
ssl = if verify_ssl.nil?
|
|
63
|
-
ENV["MELAYA_INSECURE_TLS"] != "1"
|
|
64
|
-
else
|
|
65
|
-
verify_ssl
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
http = HttpClient.new(api_key: api_key, base_url: base_url, verify_ssl: ssl)
|
|
69
|
-
|
|
70
|
-
@market = MarketAPI.new(http)
|
|
71
|
-
@account = AccountAPI.new(http)
|
|
72
|
-
@sim = SimAPI.new(http)
|
|
73
|
-
@strategies = StrategiesAPI.new(http)
|
|
74
|
-
@backtest = BacktestAPI.new(http)
|
|
75
|
-
@stream = StreamAPI.new(api_key, ws_url, http, verify_ssl: ssl)
|
|
76
|
-
@trade = TradeAPI.new(http)
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "melaya/version"
|
|
4
|
+
require_relative "melaya/errors"
|
|
5
|
+
require_relative "melaya/http_client"
|
|
6
|
+
require_relative "melaya/market"
|
|
7
|
+
require_relative "melaya/account"
|
|
8
|
+
require_relative "melaya/sim"
|
|
9
|
+
require_relative "melaya/strategies"
|
|
10
|
+
require_relative "melaya/backtest"
|
|
11
|
+
require_relative "melaya/stream"
|
|
12
|
+
require_relative "melaya/trade"
|
|
13
|
+
|
|
14
|
+
module Melaya
|
|
15
|
+
# The Melaya client.
|
|
16
|
+
#
|
|
17
|
+
# @example
|
|
18
|
+
# require "melaya"
|
|
19
|
+
# melaya = Melaya::Client.new(api_key: ENV["MK"])
|
|
20
|
+
#
|
|
21
|
+
# # Market data
|
|
22
|
+
# t = melaya.market.ticker(exchange: "binance", symbol: "BTC/USDT", market: "spot")
|
|
23
|
+
# puts t["last"]
|
|
24
|
+
#
|
|
25
|
+
# # Paper strategy
|
|
26
|
+
# result = melaya.strategies.create(
|
|
27
|
+
# name: "my-bot", strategy_type: "custom", exchange: "binanceusdm",
|
|
28
|
+
# symbol: "BTC/USDT:USDT", market: "FUTURES", dry_run: true,
|
|
29
|
+
# params: { language: "rhai", definition: 'fn evaluate() { emit_long(param("qty")); }', qty: 0.001 }
|
|
30
|
+
# )
|
|
31
|
+
# sid = result["strategyId"]
|
|
32
|
+
# melaya.strategies.stop(sid)
|
|
33
|
+
# melaya.strategies.delete(sid)
|
|
34
|
+
class Client
|
|
35
|
+
# REST market-data + reference endpoints (public plane).
|
|
36
|
+
attr_reader :market
|
|
37
|
+
# Authenticated account reads: connected keys, tier limits, usage.
|
|
38
|
+
attr_reader :account
|
|
39
|
+
# Paper trading (sim broker): virtual balance, positions, and orders.
|
|
40
|
+
attr_reader :sim
|
|
41
|
+
# Launch, control, and inspect trading strategies (paper + live).
|
|
42
|
+
attr_reader :strategies
|
|
43
|
+
# Historical backtests + parameter sweeps on the Rust engine.
|
|
44
|
+
attr_reader :backtest
|
|
45
|
+
# WebSocket streaming endpoints (public market data + private feeds).
|
|
46
|
+
attr_reader :stream
|
|
47
|
+
# Live trading — credentialed order placement and account state on a connected exchange. WARNING: real funds.
|
|
48
|
+
attr_reader :trade
|
|
49
|
+
|
|
50
|
+
# @param api_key [String] your Melaya API key, prefixed +mk_+
|
|
51
|
+
# @param base_url [String] override the REST base URL
|
|
52
|
+
# @param ws_url [String] override the WebSocket base URL
|
|
53
|
+
# @param verify_ssl [Boolean] set false to skip TLS verification (dev-box only).
|
|
54
|
+
# Prefer using ENV["MELAYA_INSECURE_TLS"]="1" rather than passing this directly.
|
|
55
|
+
def initialize(api_key:, base_url: HttpClient::DEFAULT_BASE_URL,
|
|
56
|
+
ws_url: StreamAPI::DEFAULT_WS_URL, verify_ssl: nil)
|
|
57
|
+
raise ArgumentError, "Melaya: api_key is required (create one at melaya.org -> Settings -> API Keys)." \
|
|
58
|
+
if api_key.nil? || api_key.empty?
|
|
59
|
+
raise ArgumentError, "Melaya: API keys must be prefixed 'mk_'." \
|
|
60
|
+
unless api_key.start_with?("mk_")
|
|
61
|
+
|
|
62
|
+
ssl = if verify_ssl.nil?
|
|
63
|
+
ENV["MELAYA_INSECURE_TLS"] != "1"
|
|
64
|
+
else
|
|
65
|
+
verify_ssl
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
http = HttpClient.new(api_key: api_key, base_url: base_url, verify_ssl: ssl)
|
|
69
|
+
|
|
70
|
+
@market = MarketAPI.new(http)
|
|
71
|
+
@account = AccountAPI.new(http)
|
|
72
|
+
@sim = SimAPI.new(http)
|
|
73
|
+
@strategies = StrategiesAPI.new(http)
|
|
74
|
+
@backtest = BacktestAPI.new(http)
|
|
75
|
+
@stream = StreamAPI.new(api_key, ws_url, http, verify_ssl: ssl)
|
|
76
|
+
@trade = TradeAPI.new(http)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
data/melaya.gemspec
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "lib/melaya/version"
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = "melaya"
|
|
7
|
-
spec.version = Melaya::VERSION
|
|
8
|
-
spec.authors = ["Melaya"]
|
|
9
|
-
spec.email = ["sdk@melaya.org"]
|
|
10
|
-
|
|
11
|
-
spec.summary = "Official Ruby SDK for the Melaya unified market-data & trading API"
|
|
12
|
-
spec.description = "Access 70+ exchanges via Melaya's normalized REST and WebSocket API. " \
|
|
13
|
-
"Market data, strategies, backtesting, sim trading, and streaming."
|
|
14
|
-
spec.homepage = "https://melaya.org"
|
|
15
|
-
spec.license = "MIT"
|
|
16
|
-
|
|
17
|
-
spec.required_ruby_version = ">= 3.0.0"
|
|
18
|
-
|
|
19
|
-
spec.files = Dir["lib/**/*.rb", "README.md", "melaya.gemspec"]
|
|
20
|
-
spec.require_paths = ["lib"]
|
|
21
|
-
|
|
22
|
-
# stdlib only — no runtime gem dependencies
|
|
23
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/melaya/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "melaya"
|
|
7
|
+
spec.version = Melaya::VERSION
|
|
8
|
+
spec.authors = ["Melaya"]
|
|
9
|
+
spec.email = ["sdk@melaya.org"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Official Ruby SDK for the Melaya unified market-data & trading API"
|
|
12
|
+
spec.description = "Access 70+ exchanges via Melaya's normalized REST and WebSocket API. " \
|
|
13
|
+
"Market data, strategies, backtesting, sim trading, and streaming."
|
|
14
|
+
spec.homepage = "https://melaya.org"
|
|
15
|
+
spec.license = "MIT"
|
|
16
|
+
|
|
17
|
+
spec.required_ruby_version = ">= 3.0.0"
|
|
18
|
+
|
|
19
|
+
spec.files = Dir["lib/**/*.rb", "README.md", "melaya.gemspec"]
|
|
20
|
+
spec.require_paths = ["lib"]
|
|
21
|
+
|
|
22
|
+
# stdlib only — no runtime gem dependencies
|
|
23
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: melaya
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Melaya
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-06-19 00:00:00.000000000 Z
|
|
11
12
|
dependencies: []
|
|
12
13
|
description: Access 70+ exchanges via Melaya's normalized REST and WebSocket API.
|
|
13
14
|
Market data, strategies, backtesting, sim trading, and streaming.
|
|
@@ -34,6 +35,7 @@ homepage: https://melaya.org
|
|
|
34
35
|
licenses:
|
|
35
36
|
- MIT
|
|
36
37
|
metadata: {}
|
|
38
|
+
post_install_message:
|
|
37
39
|
rdoc_options: []
|
|
38
40
|
require_paths:
|
|
39
41
|
- lib
|
|
@@ -48,7 +50,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
48
50
|
- !ruby/object:Gem::Version
|
|
49
51
|
version: '0'
|
|
50
52
|
requirements: []
|
|
51
|
-
rubygems_version:
|
|
53
|
+
rubygems_version: 3.5.22
|
|
54
|
+
signing_key:
|
|
52
55
|
specification_version: 4
|
|
53
56
|
summary: Official Ruby SDK for the Melaya unified market-data & trading API
|
|
54
57
|
test_files: []
|