kraken_bridge 0.1.0 → 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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/IMPLEMENTATION_SUMMARY.md +284 -0
  4. data/README.md +7 -2
  5. data/examples/test.rb +129 -0
  6. data/lib/kraken_bridge/client.rb +82 -0
  7. data/lib/kraken_bridge/configuration.rb +38 -0
  8. data/lib/kraken_bridge/errors/api_error.rb +19 -0
  9. data/lib/kraken_bridge/errors/authentication_error.rb +11 -0
  10. data/lib/kraken_bridge/errors/base_error.rb +14 -0
  11. data/lib/kraken_bridge/errors/connection_error.rb +11 -0
  12. data/lib/kraken_bridge/errors/rate_limit_error.rb +14 -0
  13. data/lib/kraken_bridge/errors/validation_error.rb +15 -0
  14. data/lib/kraken_bridge/middleware/error_handler.rb +166 -0
  15. data/lib/kraken_bridge/middleware/logger.rb +126 -0
  16. data/lib/kraken_bridge/middleware/rate_limiter.rb +29 -0
  17. data/lib/kraken_bridge/middleware/retry_handler.rb +97 -0
  18. data/lib/kraken_bridge/rest/authentication.rb +20 -0
  19. data/lib/kraken_bridge/rest/client.rb +20 -0
  20. data/lib/kraken_bridge/rest/connection.rb +86 -0
  21. data/lib/kraken_bridge/rest/endpoints/account.rb +92 -0
  22. data/lib/kraken_bridge/rest/endpoints/base.rb +23 -0
  23. data/lib/kraken_bridge/rest/endpoints/market_data.rb +58 -0
  24. data/lib/kraken_bridge/rest/endpoints/trading.rb +96 -0
  25. data/lib/kraken_bridge/rest/request.rb +22 -0
  26. data/lib/kraken_bridge/rest/response.rb +35 -0
  27. data/lib/kraken_bridge/utils/nonce_generator.rb +11 -0
  28. data/lib/kraken_bridge/utils/signature.rb +18 -0
  29. data/lib/kraken_bridge/version.rb +1 -1
  30. data/lib/kraken_bridge/websocket/client.rb +131 -0
  31. data/lib/kraken_bridge/websocket/connection.rb +88 -0
  32. data/lib/kraken_bridge/websocket/message_handler.rb +39 -0
  33. metadata +31 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5397bfb623a5433ebf88507b946ec3536ed334d4af933b02d8eb2f09747bb9f9
4
- data.tar.gz: 4fca7ecc5019b00cdf3e83d17df57d65648e9475c02a5de3c74082fec4e8c583
3
+ metadata.gz: 103cc2bb62587418aaaf66eaa998e57c469595696460f9a3065ed2d6d5c4a5ed
4
+ data.tar.gz: 76c17abf78c12ba5c7abaaa7de77e795df2f8cf47a8b2564571ee4f8c409bfef
5
5
  SHA512:
6
- metadata.gz: 1a12ffd53e72cbf456ceb73ec8e9720f7b74bd9092187ac65b874e122bede6b0f61feeed549f76583e4b4832ea230c2073c94861ec0d8a860735b8ebd0a7e441
7
- data.tar.gz: 58dcd2398cc142701c2ac3de14c1a4c25e84637ddc900a82f42ee9c52d5f9f1d49d42016e3f1b70192920beefb7da8e3c069fc9689bdfbcfd68e989f81f47ed9
6
+ metadata.gz: aa6ec0109f7c6de1850e3281d9c03942638cb70591097e2a4202fa597bffeb3579713fb34282fb0beefd0bf7f124631a722d421b1a0200a533ed13e198fbd782
7
+ data.tar.gz: cbb0985a92677ed4f7cfd4524af587f575b24599aa11aa8f95f93f3a62322cb907dd4ed68bd04d1027284bd238fea545bf443c65676be233f9be6b60a4bece20
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.0] - 2026-03-28
4
+
5
+ - Added Spot REST trading wrappers for `AmendOrder`, `AddOrderBatch`, `CancelOrderBatch`, and `GetWebSocketsToken`
6
+ - Expanded `CancelOrder` to support `txid`, `userref`, and `cl_ord_id`
7
+ - Added request specs for private trading and account endpoint parameter mapping
8
+
3
9
  ## [0.1.0] - 2025-12-02
4
10
 
5
11
  - Initial release
@@ -0,0 +1,284 @@
1
+ # KrakenBridge Gem - Complete Implementation Summary
2
+
3
+ ## ✅ Implementation Complete - Ready for Publishing
4
+
5
+ ### What's Included
6
+
7
+ #### 1. **REST API - Complete Implementation**
8
+
9
+ **Public Endpoints (Market Data):**
10
+ - `time` - Server time
11
+ - `system_status` - System status
12
+ - `assets` - Asset information
13
+ - `asset_pairs` - Asset pair information
14
+ - `ticker` - Ticker data
15
+ - `ohlc` - OHLC candlestick data
16
+ - `order_book` - Order book (depth)
17
+ - `trades` - Recent trades
18
+ - `spread` - Bid/ask spread
19
+
20
+ **Private Endpoints (Account):**
21
+ - `balance` - Account balance
22
+ - `extended_balance` - Extended balance
23
+ - `trade_balance` - Trade balance
24
+ - `open_orders` - Open orders
25
+ - `closed_orders` - Closed orders
26
+ - `query_orders` - Query specific orders
27
+ - `trades_history` - Trade history
28
+ - `query_trades` - Query specific trades
29
+ - `open_positions` - Open positions
30
+ - `ledger` - Account ledger
31
+ - `query_ledger` - Query ledger entries
32
+ - `trade_volume` - Trade volume
33
+ - `request_export_report` - Request export
34
+ - `get_export_report` - Get export
35
+
36
+ **Private Endpoints (Trading):**
37
+ - `add_order` - Place a new order
38
+ - `edit_order` - Edit existing order
39
+ - `cancel_order` - Cancel single order
40
+ - `cancel_all_orders` - Cancel all orders
41
+ - `cancel_all_orders_after` - Cancel after timeout
42
+
43
+ #### 2. **WebSocket - Public Feeds Implementation**
44
+
45
+ **Supported Channels:**
46
+ - **Ticker** - Real-time ticker updates
47
+ - **Trades** - Trade feed
48
+ - **OHLC/Klines** - Candlestick data
49
+ - **Spread** - Bid/ask spread updates
50
+
51
+ **Features:**
52
+ - Automatic connection management
53
+ - Subscribe/unsubscribe functionality
54
+ - Callback-based message handling
55
+ - Error handling and logging
56
+ - Connection status tracking
57
+
58
+ #### 3. **Authentication & Security**
59
+
60
+ - ✅ HMAC-SHA512 signature generation (Kraken spec compliant)
61
+ - ✅ Millisecond-precision nonce generation
62
+ - ✅ Automatic nonce injection into all authenticated requests
63
+ - ✅ 2FA (OTP) support on all authenticated endpoints
64
+ - ✅ Base64 secret decoding
65
+ - ✅ Request body ordering for signature validation
66
+
67
+ #### 4. **Core Features**
68
+
69
+ - ✅ Rate limiting (configurable)
70
+ - ✅ Automatic retries with exponential backoff
71
+ - ✅ Comprehensive error handling
72
+ - ✅ Request/response logging
73
+ - ✅ Configuration management
74
+ - ✅ Standardized response objects
75
+ - ✅ Custom error classes
76
+
77
+ #### 5. **Documentation**
78
+
79
+ **Files Created/Updated:**
80
+ - `README.md` - Comprehensive guide with:
81
+ - Quick start examples
82
+ - Configuration options
83
+ - Full API reference
84
+ - Error handling patterns
85
+ - Security recommendations
86
+ - Troubleshooting guide
87
+ - References and links
88
+
89
+ - `AUTHENTICATION_FIXES.md` - Technical details on authentication implementation
90
+ - `TESTING_AUTHENTICATED_ENDPOINTS.md` - Testing guide with examples
91
+
92
+ ### File Structure
93
+
94
+ ```
95
+ kraken_bridge/
96
+ ├── lib/
97
+ │ ├── kraken_bridge.rb (main entry point)
98
+ │ └── kraken_bridge/
99
+ │ ├── client.rb (main client)
100
+ │ ├── configuration.rb
101
+ │ ├── version.rb
102
+ │ ├── rest/
103
+ │ │ ├── client.rb
104
+ │ │ ├── connection.rb
105
+ │ │ ├── request.rb
106
+ │ │ ├── response.rb
107
+ │ │ ├── authentication.rb
108
+ │ │ └── endpoints/
109
+ │ │ ├── base.rb
110
+ │ │ ├── market_data.rb
111
+ │ │ ├── account.rb
112
+ │ │ └── trading.rb
113
+ │ ├── websocket/
114
+ │ │ ├── client.rb
115
+ │ │ ├── connection.rb
116
+ │ │ └── message_handler.rb
117
+ │ ├── utils/
118
+ │ │ ├── nonce_generator.rb
119
+ │ │ └── signature.rb
120
+ │ ├── middleware/
121
+ │ │ ├── rate_limiter.rb
122
+ │ │ ├── retry_handler.rb
123
+ │ │ ├── logger.rb
124
+ │ │ └── error_handler.rb
125
+ │ └── errors/
126
+ │ ├── base_error.rb
127
+ │ ├── api_error.rb
128
+ │ ├── authentication_error.rb
129
+ │ ├── rate_limit_error.rb
130
+ │ ├── connection_error.rb
131
+ │ └── validation_error.rb
132
+ ├── spec/ (test files)
133
+ ├── README.md
134
+ ├── CHANGELOG.md
135
+ ├── LICENSE.txt
136
+ ├── Gemfile
137
+ ├── kraken_bridge.gemspec
138
+ └── Rakefile
139
+ ```
140
+
141
+ ### Usage Examples
142
+
143
+ #### Public API
144
+ ```ruby
145
+ client = KrakenBridge::Client.new
146
+ ticker = client.market_data.ticker(['XBTUSD'])
147
+ puts ticker.data
148
+ ```
149
+
150
+ #### Private API (with authentication)
151
+ ```ruby
152
+ client = KrakenBridge::Client.new(
153
+ api_key: ENV['KRAKEN_API_KEY'],
154
+ api_secret: ENV['KRAKEN_API_SECRET']
155
+ )
156
+ balance = client.account.balance
157
+ puts balance.data
158
+ ```
159
+
160
+ #### WebSocket Real-time Data
161
+ ```ruby
162
+ client = KrakenBridge::Client.new
163
+
164
+ client.connect_websocket do |message|
165
+ puts message
166
+ end
167
+
168
+ client.subscribe_ticker(['XBTUSD']) do |data|
169
+ puts "Ticker: #{data}"
170
+ end
171
+
172
+ sleep(30)
173
+ client.disconnect_websocket
174
+ ```
175
+
176
+ ### Dependencies
177
+
178
+ ```ruby
179
+ # Runtime
180
+ websocket-client-simple ~> 0.8
181
+
182
+ # Development
183
+ bundler ~> 2.0
184
+ rake ~> 13.0
185
+ rspec ~> 3.12
186
+ rubocop ~> 1.50
187
+ rubocop-rspec ~> 2.20
188
+ vcr ~> 6.1
189
+ webmock ~> 3.18
190
+ simplecov ~> 0.22
191
+ yard ~> 0.9
192
+ ```
193
+
194
+ ### Publishing Steps
195
+
196
+ 1. **Update version** in `lib/kraken_bridge/version.rb`
197
+ ```ruby
198
+ VERSION = '1.0.0'
199
+ ```
200
+
201
+ 2. **Build the gem**
202
+ ```bash
203
+ bundle exec rake build
204
+ ```
205
+
206
+ 3. **Test locally**
207
+ ```bash
208
+ bundle exec rspec
209
+ ```
210
+
211
+ 4. **Push to RubyGems**
212
+ ```bash
213
+ gem push pkg/kraken_bridge-1.0.0.gem
214
+ ```
215
+
216
+ 5. **Update gemspec metadata**
217
+ - Set proper homepage URL
218
+ - Add description
219
+ - Configure allowed_push_host
220
+
221
+ ### Current Status
222
+
223
+ ✅ **All Features Implemented**
224
+ ✅ **Authentication Working**
225
+ ✅ **Private APIs Tested**
226
+ ✅ **WebSocket Implementation Complete**
227
+ ✅ **Documentation Complete**
228
+ ✅ **Code Quality**
229
+ ✅ **Ready for Publishing**
230
+
231
+ ### Next Steps for Publishing
232
+
233
+ 1. Update `kraken_bridge.gemspec`:
234
+ ```ruby
235
+ spec.summary = "Ruby client for Kraken cryptocurrency exchange API"
236
+ spec.description = "Comprehensive REST and WebSocket integration with Kraken"
237
+ spec.homepage = "https://github.com/balram/kraken_bridge"
238
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
239
+ spec.metadata['source_code_uri'] = "https://github.com/balram/kraken_bridge"
240
+ spec.metadata['changelog_uri'] = "https://github.com/balram/kraken_bridge/blob/master/CHANGELOG.md"
241
+ ```
242
+
243
+ 2. Run final tests
244
+ ```bash
245
+ bundle exec rspec
246
+ bundle exec rubocop
247
+ ```
248
+
249
+ 3. Create git tag
250
+ ```bash
251
+ git tag -a v1.0.0 -m "Release version 1.0.0"
252
+ ```
253
+
254
+ 4. Push to RubyGems
255
+ ```bash
256
+ gem build kraken_bridge.gemspec
257
+ gem push kraken_bridge-1.0.0.gem
258
+ ```
259
+
260
+ ### Key Features Implemented
261
+
262
+ | Feature | Status | Details |
263
+ |---------|--------|---------|
264
+ | REST API (Public) | ✅ | All market data endpoints |
265
+ | REST API (Private) | ✅ | Account & Trading endpoints |
266
+ | WebSocket | ✅ | Ticker, Trades, OHLC, Spread |
267
+ | Authentication | ✅ | HMAC-SHA512 per Kraken spec |
268
+ | Nonce Generation | ✅ | Millisecond precision |
269
+ | 2FA Support | ✅ | OTP parameter support |
270
+ | Rate Limiting | ✅ | Built-in & configurable |
271
+ | Error Handling | ✅ | Custom error classes |
272
+ | Logging | ✅ | Configurable debug logging |
273
+ | Documentation | ✅ | Comprehensive README |
274
+
275
+ ### Security Verified
276
+
277
+ - ✅ Proper signature generation (HMAC-SHA512)
278
+ - ✅ Base64 secret decoding
279
+ - ✅ Nonce in milliseconds
280
+ - ✅ No API keys in code
281
+ - ✅ Environment variable support
282
+ - ✅ 2FA-ready implementation
283
+
284
+
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # KrakenBridge
2
2
 
3
- A comprehensive Ruby gem for seamless integration with Kraken cryptocurrency exchange APIs. Supports both REST and WebSocket protocols for public market data and authenticated trading operations.
3
+ A Ruby gem for Kraken cryptocurrency exchange APIs. Supports Spot REST workflows for market data and core authenticated trading, plus public WebSocket feeds.
4
4
 
5
5
  ## Features
6
6
 
7
- - ✅ **Complete REST API Support**: Public and private endpoints
7
+ - ✅ **Spot REST Coverage for Core Workflows**: Market data, account queries, and trading operations
8
8
  - ✅ **WebSocket Real-time Feeds**: Ticker, trades, OHLC/Klines, and spread data
9
9
  - ✅ **Automatic Nonce Generation**: Millisecond-precision timestamps
10
10
  - ✅ **Signature Generation**: HMAC-SHA512 authentication per Kraken specs
@@ -179,10 +179,15 @@ client.account.get_export_report(report: 'trades')
179
179
 
180
180
  ```ruby
181
181
  client.trading.add_order(pair: 'XBTUSD', type: 'buy', ordertype: 'limit', volume: 0.01, price: 25000)
182
+ client.trading.amend_order(txid: 'order_id', order_qty: 0.02, limit_price: '26000')
183
+ client.trading.add_order_batch(pair: 'XBTUSD', orders: [{ ordertype: 'limit', type: 'buy', volume: '0.01', price: '25000' }, { ordertype: 'limit', type: 'sell', volume: '0.01', price: '26000' }])
184
+ client.trading.get_websockets_token
182
185
  client.trading.edit_order(txid: 'order_id', volume: 0.02, price: 26000)
183
186
  client.trading.cancel_order('order_id')
187
+ client.trading.cancel_order(cl_ord_id: 'client-order-id')
184
188
  client.trading.cancel_all_orders
185
189
  client.trading.cancel_all_orders_after(timeout: 300)
190
+ client.trading.cancel_order_batch(txid: ['order_id_1', 'order_id_2'])
186
191
  ```
187
192
 
188
193
  ### WebSocket (Public Feeds)
data/examples/test.rb ADDED
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative 'lib/kraken_bridge'
4
+
5
+ # Initialize client
6
+ client = KrakenBridge::Client.new(
7
+ api_key: ENV.fetch('KRAKEN_API_KEY', nil),
8
+ api_secret: ENV.fetch('KRAKEN_API_SECRET', nil)
9
+ )
10
+
11
+ puts('=' * 80)
12
+ puts 'KRAKEN BRIDGE - API EXAMPLES'
13
+ puts('=' * 80)
14
+
15
+ # PUBLIC API EXAMPLES
16
+ puts "\n\n"
17
+ puts('=' * 80)
18
+ puts 'PUBLIC API EXAMPLES (No Authentication Required)'
19
+ puts('=' * 80)
20
+
21
+ puts "\n1. SERVER TIME"
22
+ puts('-' * 80)
23
+ time_response = client.market_data.time
24
+ puts time_response.data if time_response.success?
25
+
26
+ puts "\n2. SYSTEM STATUS"
27
+ puts('-' * 80)
28
+ status_response = client.market_data.system_status
29
+ puts status_response.data if status_response.success?
30
+
31
+ puts "\n3. ASSET INFORMATION"
32
+ puts('-' * 80)
33
+ assets_response = client.market_data.assets(assets: %w[BTC ETH])
34
+ puts assets_response.data if assets_response.success?
35
+
36
+ puts "\n4. ASSET PAIRS"
37
+ puts('-' * 80)
38
+ pairs_response = client.market_data.asset_pairs(pairs: %w[XBTUSD ETHUSD])
39
+ puts pairs_response.data if pairs_response.success?
40
+
41
+ puts "\n5. TICKER INFORMATION"
42
+ puts('-' * 80)
43
+ ticker_response = client.market_data.ticker(%w[XBTUSD ETHUSD])
44
+ puts ticker_response.data if ticker_response.success?
45
+
46
+ puts "\n6. OHLC DATA"
47
+ puts('-' * 80)
48
+ ohlc_response = client.market_data.ohlc('XBTUSD', interval: 1)
49
+ puts ohlc_response.data if ohlc_response.success?
50
+
51
+ puts "\n7. ORDER BOOK (Depth)"
52
+ puts('-' * 80)
53
+ orderbook_response = client.market_data.order_book('XBTUSD')
54
+ puts orderbook_response.data if orderbook_response.success?
55
+
56
+ puts "\n8. RECENT TRADES"
57
+ puts('-' * 80)
58
+ trades_response = client.market_data.trades('XBTUSD')
59
+ puts trades_response.data if trades_response.success?
60
+
61
+ puts "\n9. SPREAD"
62
+ puts('-' * 80)
63
+ spread_response = client.market_data.spread('XBTUSD')
64
+ puts spread_response.data if spread_response.success?
65
+
66
+ # PRIVATE API EXAMPLES (Requires API Credentials)
67
+ if ENV['KRAKEN_API_KEY'] && ENV['KRAKEN_API_SECRET']
68
+ puts "\n\n"
69
+ puts('=' * 80)
70
+ puts 'PRIVATE API EXAMPLES (Requires Authentication)'
71
+ puts('=' * 80)
72
+
73
+ puts "\n10. ACCOUNT BALANCE"
74
+ puts('-' * 80)
75
+ balance_response = client.account.balance
76
+ puts balance_response.data if balance_response.success?
77
+ puts balance_response.errors unless balance_response.success?
78
+
79
+ puts "\n11. EXTENDED BALANCE"
80
+ puts('-' * 80)
81
+ ext_balance_response = client.account.extended_balance
82
+ puts ext_balance_response.data if ext_balance_response.success?
83
+
84
+ puts "\n12. TRADE BALANCE"
85
+ puts('-' * 80)
86
+ trade_balance_response = client.account.trade_balance
87
+ puts trade_balance_response.data if trade_balance_response.success?
88
+
89
+ puts "\n13. OPEN ORDERS"
90
+ puts('-' * 80)
91
+ open_orders_response = client.account.open_orders
92
+ puts open_orders_response.data if open_orders_response.success?
93
+
94
+ puts "\n14. CLOSED ORDERS"
95
+ puts('-' * 80)
96
+ closed_orders_response = client.account.closed_orders
97
+ puts closed_orders_response.data if closed_orders_response.success?
98
+
99
+ puts "\n15. TRADES HISTORY"
100
+ puts('-' * 80)
101
+ trades_history_response = client.account.trades_history
102
+ puts trades_history_response.data if trades_history_response.success?
103
+
104
+ puts "\n16. OPEN POSITIONS"
105
+ puts('-' * 80)
106
+ positions_response = client.account.open_positions
107
+ puts positions_response.data if positions_response.success?
108
+
109
+ puts "\n17. LEDGER"
110
+ puts('-' * 80)
111
+ ledger_response = client.account.ledger
112
+ puts ledger_response.data if ledger_response.success?
113
+
114
+ puts "\n18. TRADE VOLUME"
115
+ puts('-' * 80)
116
+ volume_response = client.account.trade_volume
117
+ puts volume_response.data if volume_response.success?
118
+ end
119
+
120
+ puts "\n\n"
121
+ puts('=' * 80)
122
+ puts 'WEBSOCKET EXAMPLES (Public Feeds)'
123
+ puts('=' * 80)
124
+
125
+ puts "\nWebSocket Features Available:"
126
+ puts '- Subscribe to ticker data'
127
+ puts '- Subscribe to trades'
128
+ puts '- Subscribe to OHLC/Klines'
129
+ puts '- Subscribe to spread data'
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KrakenBridge
4
+ class Client
5
+ attr_reader :rest, :websocket, :config
6
+
7
+ def initialize(api_key: nil, api_secret: nil, **options)
8
+ @config = KrakenBridge.configuration.dup
9
+ @config.api_key = api_key if api_key
10
+ @config.api_secret = api_secret if api_secret
11
+
12
+ options.each do |key, value|
13
+ @config.send("#{key}=", value) if @config.respond_to?("#{key}=")
14
+ end
15
+
16
+ @rest = Rest::Client.new(@config)
17
+ @websocket = Websocket::Client.new(@config)
18
+ end
19
+
20
+ def market_data
21
+ rest.market_data
22
+ end
23
+
24
+ def account
25
+ rest.account
26
+ end
27
+
28
+ def trading
29
+ rest.trading
30
+ end
31
+
32
+ def ticker(pair)
33
+ rest.market_data.ticker(pair)
34
+ end
35
+
36
+ def trades(pair, since: nil)
37
+ rest.market_data.trades(pair, since: since)
38
+ end
39
+
40
+ def ohlc(pair, interval: 1, since: nil)
41
+ rest.market_data.ohlc(pair, interval: interval, since: since)
42
+ end
43
+
44
+ def balance
45
+ rest.account.balance
46
+ end
47
+
48
+ def place_order(pair:, type:, order_type:, volume:, **options)
49
+ rest.trading.add_order(
50
+ pair: pair,
51
+ type: type,
52
+ ordertype: order_type,
53
+ volume: volume,
54
+ **options
55
+ )
56
+ end
57
+
58
+ def subscribe_ticker(pairs, &)
59
+ websocket.subscribe_ticker(pairs, &)
60
+ end
61
+
62
+ def subscribe_trades(pairs, &)
63
+ websocket.subscribe_trades(pairs, &)
64
+ end
65
+
66
+ def subscribe_ohlc(pairs, interval: 1, &block)
67
+ websocket.subscribe_ohlc(pairs, interval: interval, &block)
68
+ end
69
+
70
+ def subscribe_klines(pairs, interval: 1, &block)
71
+ websocket.subscribe_klines(pairs, interval: interval, &block)
72
+ end
73
+
74
+ def connect_websocket(&)
75
+ websocket.connect(&)
76
+ end
77
+
78
+ def disconnect_websocket
79
+ websocket.disconnect
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KrakenBridge
4
+ class Configuration
5
+ attr_accessor :api_key, :api_secret, :rest_url, :ws_url,
6
+ :timeout, :open_timeout, :logger, :log_level,
7
+ :rate_limit_enabled, :retry_enabled, :max_retries
8
+
9
+ def initialize
10
+ @api_key = ENV.fetch('KRAKEN_API_KEY', nil)
11
+ @api_secret = ENV.fetch('KRAKEN_API_SECRET', nil)
12
+ @rest_url = ENV['KRAKEN_API_URL'] || 'https://api.kraken.com'
13
+ @ws_url = ENV['KRAKEN_WEBSOCKET_URL'] || 'wss://ws.kraken.com'
14
+ @timeout = 30
15
+ @open_timeout = 10
16
+ @log_level = Logger::INFO
17
+ @logger = Middleware::Logger.new(::Logger.new($stdout))
18
+ @rate_limit_enabled = true
19
+ @retry_enabled = true
20
+ @max_retries = 3
21
+
22
+ configure_logger
23
+ end
24
+
25
+ def credentials_present?
26
+ !api_key.nil? && !api_secret.nil?
27
+ end
28
+
29
+ private
30
+
31
+ def configure_logger
32
+ @logger.logger.level = @log_level
33
+ @logger.logger.formatter = proc do |severity, datetime, _progname, msg|
34
+ "[#{datetime.strftime('%Y-%m-%d %H:%M:%S')}] #{severity} -- #{msg}\n"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KrakenBridge
4
+ module Errors
5
+ class ApiError < BaseError
6
+ attr_reader :error_codes, :response
7
+
8
+ def initialize(message, error_codes = [], response = nil)
9
+ @error_codes = error_codes
10
+ @response = response
11
+ super(message)
12
+ end
13
+
14
+ def error_messages
15
+ error_codes.join(', ')
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KrakenBridge
4
+ module Errors
5
+ class AuthenticationError < BaseError
6
+ def initialize(message = 'Authentication failed')
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KrakenBridge
4
+ module Errors
5
+ class BaseError < StandardError
6
+ attr_reader :original_error
7
+
8
+ def initialize(message = nil, original_error = nil)
9
+ @original_error = original_error
10
+ super(message)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KrakenBridge
4
+ module Errors
5
+ class ConnectionError < BaseError
6
+ def initialize(message = 'Connection failed', original_error = nil)
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KrakenBridge
4
+ module Errors
5
+ class RateLimitError < BaseError
6
+ attr_reader :retry_after
7
+
8
+ def initialize(message, retry_after = nil)
9
+ @retry_after = retry_after
10
+ super(message)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KrakenBridge
4
+ module Errors
5
+ class ValidationError < BaseError
6
+ attr_reader :field, :value
7
+
8
+ def initialize(message, field: nil, value: nil)
9
+ @field = field
10
+ @value = value
11
+ super(message)
12
+ end
13
+ end
14
+ end
15
+ end