delta_exchange 0.1.2

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 (57) hide show
  1. checksums.yaml +7 -0
  2. data/.cursor/.gitignore +1 -0
  3. data/CHANGELOG.md +11 -0
  4. data/CODE_OF_CONDUCT.md +10 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +253 -0
  7. data/Rakefile +12 -0
  8. data/docs/AUTHENTICATION.md +49 -0
  9. data/docs/GETTING_STARTED.md +67 -0
  10. data/docs/RAILS_INTEGRATION.md +135 -0
  11. data/docs/REST_API_GUIDE.md +150 -0
  12. data/docs/STANDALONE_RUBY_GUIDE.md +73 -0
  13. data/docs/WEBSOCKET_GUIDE.md +160 -0
  14. data/exe/delta_exchange +4 -0
  15. data/lib/delta_exchange/auth.rb +12 -0
  16. data/lib/delta_exchange/client.rb +196 -0
  17. data/lib/delta_exchange/configuration.rb +40 -0
  18. data/lib/delta_exchange/constants.rb +72 -0
  19. data/lib/delta_exchange/contracts/order_contract.rb +24 -0
  20. data/lib/delta_exchange/contracts/position_contract.rb +21 -0
  21. data/lib/delta_exchange/contracts/wallet_transfer_contract.rb +16 -0
  22. data/lib/delta_exchange/core/base_model.rb +54 -0
  23. data/lib/delta_exchange/core/error_handler.rb +16 -0
  24. data/lib/delta_exchange/error.rb +37 -0
  25. data/lib/delta_exchange/helpers/attribute_helper.rb +22 -0
  26. data/lib/delta_exchange/helpers/validation_helper.rb +34 -0
  27. data/lib/delta_exchange/models/asset.rb +23 -0
  28. data/lib/delta_exchange/models/fee_tier.rb +19 -0
  29. data/lib/delta_exchange/models/fill.rb +20 -0
  30. data/lib/delta_exchange/models/funding_rate.rb +19 -0
  31. data/lib/delta_exchange/models/index.rb +23 -0
  32. data/lib/delta_exchange/models/open_interest.rb +19 -0
  33. data/lib/delta_exchange/models/order.rb +34 -0
  34. data/lib/delta_exchange/models/position.rb +43 -0
  35. data/lib/delta_exchange/models/product.rb +43 -0
  36. data/lib/delta_exchange/models/profile.rb +20 -0
  37. data/lib/delta_exchange/models/ticker.rb +26 -0
  38. data/lib/delta_exchange/models/trading_preferences.rb +27 -0
  39. data/lib/delta_exchange/models/wallet_balance.rb +23 -0
  40. data/lib/delta_exchange/models/wallet_transaction.rb +20 -0
  41. data/lib/delta_exchange/resources/account.rb +53 -0
  42. data/lib/delta_exchange/resources/assets.rb +11 -0
  43. data/lib/delta_exchange/resources/base.rb +37 -0
  44. data/lib/delta_exchange/resources/fills.rb +15 -0
  45. data/lib/delta_exchange/resources/heartbeat.rb +20 -0
  46. data/lib/delta_exchange/resources/indices.rb +11 -0
  47. data/lib/delta_exchange/resources/market_data.rb +56 -0
  48. data/lib/delta_exchange/resources/orders.rb +76 -0
  49. data/lib/delta_exchange/resources/positions.rb +47 -0
  50. data/lib/delta_exchange/resources/products.rb +39 -0
  51. data/lib/delta_exchange/resources/wallet.rb +45 -0
  52. data/lib/delta_exchange/version.rb +5 -0
  53. data/lib/delta_exchange/websocket/client.rb +55 -0
  54. data/lib/delta_exchange/websocket/connection.rb +114 -0
  55. data/lib/delta_exchange.rb +39 -0
  56. data/sig/delta_exchange.rbs +4 -0
  57. metadata +231 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7e237fcff01ceb49340e97b9488881c8db98854360a69d44f809bb7eb2714dac
4
+ data.tar.gz: 10f2351163211453f02454f6d1b22d53dbea71d6ec4e3b26de7479720438ac1b
5
+ SHA512:
6
+ metadata.gz: 28e3ed680eaa5d5f88cfb715eb3f4288b9b71657801a0237c608d1bbb307a89b1c8610d5e8a3fe2cfe407237edd1d39a79a1758f36518fb475c324ee17ee6047
7
+ data.tar.gz: bb3e23553b102c42264682ff961ca427179fc39d8e1302020e94a352c71380a87f1aed032cfab5f0aa9b8eae9bcc8e61dc117aed5a965a050062846cd75eaad8
@@ -0,0 +1 @@
1
+ plans/
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.2] - 2026-03-25
4
+ ### Changed
5
+ - Refactored `Models` namespace wrapper classes to invoke resource dependencies through a global lazy `DeltaExchange.client` factory, enforcing Dependency Injection boundaries natively and patching `ArgumentError` crashes.
6
+ - Hardened WebSockets `Faye` bindings and stabilized internal EventMachine reactor loops bridging payload sockets directly over Testnet domain gateways.
7
+ - Expanded core client capabilities utilizing dynamic `set_leverage` modifiers, VCR-tested Dry-Validation wrappers, and exhaustive test coverage matrices shielding internal `raise ApiError` resolutions.
8
+
9
+ ## [0.1.1] - 2026-03-21
10
+
11
+ - Initial release
@@ -0,0 +1,10 @@
1
+ # Code of Conduct
2
+
3
+ "delta_exchange" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
4
+
5
+ * Participants will be tolerant of opposing views.
6
+ * Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
7
+ * When interpreting the words and actions of others, participants should always assume good intentions.
8
+ * Behaviour which can be reasonably considered harassment will not be tolerated.
9
+
10
+ If you have any concerns about behaviour within this project, please contact us at ["shubhamtaywade82@gmail.com"](mailto:"shubhamtaywade82@gmail.com").
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Shubham Taywade
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # DeltaExchange
2
+
3
+ A Ruby client for the Delta Exchange API.
4
+
5
+ ![Ruby Version](https://img.shields.io/badge/ruby-%3E%3D%203.2.0-red)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Quick Links
9
+
10
+ | Resource | Document | Description |
11
+ |----------|----------|-------------|
12
+ | **Orders** | [REST API Guide](docs/REST_API_GUIDE.md#orders) | Create, manage, and cancel orders |
13
+ | **Products** | [REST API Guide](docs/REST_API_GUIDE.md#products) | Fetch trading pairs and market specs |
14
+ | **WebSocket** | [WebSocket Guide](docs/WEBSOCKET_GUIDE.md) | Real-time data streams |
15
+ | **Auth** | [Authentication](docs/AUTHENTICATION.md) | API Key & Signature management |
16
+
17
+ ---
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'delta_exchange'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ $ bundle install
30
+
31
+ Or install it yourself as:
32
+
33
+ $ gem install delta_exchange
34
+
35
+ ## Releasing
36
+
37
+ Publishing is handled by GitHub Actions when a version tag is pushed.
38
+
39
+ ### One-time RubyGems setup
40
+
41
+ Configure `delta_exchange` as a trusted publisher on RubyGems.org:
42
+
43
+ 1. Open the gem page on RubyGems.org and manage trusted publishers.
44
+ 2. Add this GitHub repository:
45
+ - Owner: `shubhamtaywade82`
46
+ - Repository: `delta_exchange`
47
+ - Workflow file: `release.yml`
48
+ - Environment: `release`
49
+ 3. Save the publisher configuration.
50
+
51
+ This uses GitHub OIDC trusted publishing, so the workflow does not need a long-lived `RUBYGEMS_API_KEY` or OTP secret. RubyGems must match all four values exactly.
52
+
53
+ ### Release a new version
54
+
55
+ 1. Update `lib/delta_exchange/version.rb`.
56
+ 2. Update `CHANGELOG.md`.
57
+ 3. Merge the changes to `main`.
58
+ 4. Create and push a matching tag:
59
+
60
+ ```bash
61
+ git tag v0.1.2
62
+ git push origin v0.1.2
63
+ ```
64
+
65
+ The release workflow validates that the tag matches `DeltaExchange::VERSION` before publishing the gem to RubyGems.org.
66
+
67
+ ## Documentation
68
+
69
+ For detailed guides and examples, see:
70
+
71
+ * [Getting Started](docs/GETTING_STARTED.md)
72
+ * [Authentication Guide](docs/AUTHENTICATION.md)
73
+ * [REST API Guide](docs/REST_API_GUIDE.md)
74
+ * [WebSocket Guide](docs/WEBSOCKET_GUIDE.md)
75
+ * [Rails Integration](docs/RAILS_INTEGRATION.md)
76
+ * [Standalone Ruby Guide](docs/STANDALONE_RUBY_GUIDE.md)
77
+
78
+ ## Usage
79
+
80
+ ### Configuration
81
+
82
+ ```ruby
83
+ DeltaExchange.configure do |config|
84
+ config.api_key = ENV['DELTA_API_KEY'] || 'YOUR_API_KEY'
85
+ config.api_secret = ENV['DELTA_API_SECRET'] || 'YOUR_API_SECRET'
86
+ config.testnet = true # Optional, defaults to false
87
+ config.websocket_reconnect_delay = 5 # Optional, defaults to 5 seconds
88
+ end
89
+ ```
90
+
91
+ **Note:** If you are testing the client via `./bin/console`, it will automatically load any variables from a `.env` file in the root directory into `ENV`.
92
+
93
+ ### REST API
94
+
95
+ The client employs a highly robust **ActiveRecord**-style abstraction via the `DeltaExchange::Models::` namespace. Rather than interacting with raw unstructured JSON payloads via `Client.new`, you query the platform utilizing structured properties and class-level queries.
96
+
97
+ #### 1. Products & Market Data
98
+ Retrieve available trading pairs, orderbooks, and option chains natively.
99
+ ```ruby
100
+ # Get all products (returns array of Models::Product)
101
+ DeltaExchange::Models::Product.all
102
+
103
+ product = DeltaExchange::Models::Product.find('BTCUSD')
104
+ puts product.contract_type # "perpetual_futures"
105
+
106
+ # Get all live tickers and access price via .close (India API standard)
107
+ ticker = DeltaExchange::Models::Ticker.find('BTCUSD')
108
+ puts "Current Price: #{ticker.close}"
109
+
110
+ # Get all live tickers
111
+ DeltaExchange::Models::Ticker.all
112
+
113
+ # Mutating methods like set_leverage return the raw API response hash
114
+ response = product.set_leverage(50)
115
+ puts "New Leverage: #{response[:leverage]}"
116
+ ```
117
+
118
+ #### 2. Orders
119
+ Create, manage, and cancel your active orders.
120
+ ```ruby
121
+ # Create a new order (Returns a Models::Order)
122
+ order = DeltaExchange::Models::Order.create({
123
+ product_id: 1,
124
+ size: 10,
125
+ side: 'buy',
126
+ order_type: 'limit_order',
127
+ limit_price: '50000'
128
+ })
129
+
130
+ # Access properties
131
+ puts order.status # "open"
132
+
133
+ # List your active orders
134
+ DeltaExchange::Models::Order.all
135
+
136
+ # Cancel the order directly from its instance
137
+ order.cancel
138
+ ```
139
+
140
+ #### 3. Positions & Fills
141
+ Track open derivatives positions and execution histories cleanly.
142
+
143
+ You can instantly execute commands atop the models natively using class methods. This bypasses structural scaffolding because the library manages connections globally by default!
144
+
145
+ ```ruby
146
+ # Retrieve Native Ruby Objects instead of messy Array Hashes
147
+ orders = DeltaExchange::Models::Order.all
148
+
149
+ # Manipulate endpoints using direct class directives
150
+ DeltaExchange::Models::Position.close_all(
151
+ product_id: 27 # BTCUSD testnet
152
+ )
153
+
154
+ # Find an isolated position by Product ID
155
+ position = DeltaExchange::Models::Position.find(1)
156
+
157
+ # Modify your isolated positions natively
158
+ position.adjust_margin('150.5', type: 'add')
159
+ position.set_auto_topup(true)
160
+
161
+ # Retrieve recent trade fills (Returns an array of Models::Fill)
162
+ DeltaExchange::Models::Fill.all(product_id: 1, limit: 50)
163
+ ```
164
+
165
+ #### 4. Account & Wallet
166
+ Monitor balances and configure account-level preferences.
167
+ ```ruby
168
+ # Get wallet balances across all assets
169
+ DeltaExchange::Models::WalletBalance.all
170
+
171
+ # Isolate a specific currency balance
172
+ btc_balance = DeltaExchange::Models::WalletBalance.find_by_asset('BTC')
173
+
174
+ # List recent wallet transactions
175
+ DeltaExchange::Models::WalletTransaction.all
176
+
177
+ # View your user profile details
178
+ profile = DeltaExchange::Models::Profile.fetch
179
+ puts "Hello #{profile.first_name}!"
180
+
181
+ # Update trading preferences natively
182
+ prefs = DeltaExchange::Models::TradingPreferences.fetch
183
+ puts "User ID: #{prefs.user_id}"
184
+ prefs.update(cancel_on_disconnect: true)
185
+ ```
186
+
187
+ #### 5. Assets & Indices
188
+ Pull infrastructure parameters mapping indices to component assets.
189
+ ```ruby
190
+ # Get all platform assets
191
+ DeltaExchange::Models::Asset.all
192
+
193
+ # Get all tracked indices
194
+ DeltaExchange::Models::Index.all
195
+ ```
196
+
197
+ ### Error Handling
198
+
199
+ The gem wraps network and API responses within native Ruby classes.
200
+
201
+ ```ruby
202
+ begin
203
+ client.orders.create({ product_id: 999999, size: 10 })
204
+ rescue DeltaExchange::RateLimitError => e
205
+ puts "Rate limited! Retry after #{e.retry_after_seconds} seconds"
206
+ rescue DeltaExchange::ApiError => e
207
+ puts "API rejected the request: #{e.message} (Code: #{e.code})"
208
+ rescue DeltaExchange::NetworkError => e
209
+ puts "Could not connect: #{e.message}"
210
+ end
211
+ ```
212
+
213
+ ### WebSocket
214
+
215
+ > [!IMPORTANT]
216
+ > The WebSocket client uses EventMachine in a detached thread. While the gem handles automatic reconnections, you must ensure your main process remains alive (e.g., via `loop { sleep 1 }` or joining the EM thread).
217
+
218
+ ```ruby
219
+ ws = DeltaExchange::Websocket::Client.new
220
+
221
+ ws.on :open do |event|
222
+ puts "Connected!"
223
+ ws.subscribe([
224
+ { name: "v2/ticker", symbols: ["BTCUSD"] }
225
+ ])
226
+ end
227
+
228
+ ws.on :message do |data|
229
+ puts "Received: #{data}"
230
+ end
231
+
232
+ ws.connect!
233
+
234
+ # Keep the main thread alive if necessary
235
+ loop { sleep 1 }
236
+ ```
237
+
238
+ ## Debugging
239
+
240
+ You can enable HTTP traffic logging via the command-line environment variables.
241
+ The `api-key` and `signature` headers are **automatically redacted** during debug rendering to protect your credentials.
242
+
243
+ ```bash
244
+ DELTA_DEBUG=true ruby app.rb
245
+ ```
246
+
247
+ ## Contributing
248
+
249
+ Bug reports and pull requests are welcome on GitHub at https://github.com/shubhamtaywade82/delta_exchange.
250
+
251
+ ## License
252
+
253
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,49 @@
1
+ # Authentication Details
2
+
3
+ DeltaExchange v2 uses a signature-based authentication method (HMAC-SHA256).
4
+
5
+ ## Credentials Needed
6
+
7
+ 1. **API Key**: A unique key provided by Delta Exchange.
8
+ 2. **API Secret**: Used to sign requests (never share this!).
9
+
10
+ ## Configuration Methods
11
+
12
+ ### Block-style (Recommended for Initializers)
13
+
14
+ ```ruby
15
+ DeltaExchange.configure do |config|
16
+ config.api_key = ENV['DELTA_API_KEY']
17
+ config.api_secret = ENV['DELTA_API_SECRET']
18
+ config.testnet = true # Set to false for production
19
+ end
20
+ ```
21
+
22
+ ### Direct Initialization
23
+
24
+ You can also pass credentials directly when creating a client:
25
+
26
+ ```ruby
27
+ client = DeltaExchange::Client.new(
28
+ api_key: 'custom_key',
29
+ api_secret: 'custom_secret',
30
+ testnet: false
31
+ )
32
+ ```
33
+
34
+ ## Security Best Practices
35
+
36
+ * **Environment Variables**: Never hardcode your API keys in the source code. Use gems like `dotenv` or Rails Credentials.
37
+ * **IP Whitelisting**: For production, it is highly recommended to whitelist your server's IP in your Delta Exchange API settings.
38
+ * **Permissions**: Only enable the permissions your bot needs (e.g., "Read" and "Trade"). Avoid "Withdrawal" permissions unless necessary.
39
+
40
+ ## How the Gem Signs Requests
41
+
42
+ The gem handles signature generation automatically for every authenticated request. The pre-hash string follows the format:
43
+ `method + timestamp + path + query_string + payload`
44
+
45
+ Example internal logic:
46
+ ```ruby
47
+ signature = OpenSSL::HMAC.hexdigest("SHA256", secret, prehash_string)
48
+ ```
49
+ This is fully encapsulated in the `DeltaExchange::Auth` module.
@@ -0,0 +1,67 @@
1
+ # Getting Started with DeltaExchange
2
+
3
+ DeltaExchange is a powerful Ruby gem designed for algorithmic trading on the Delta Exchange India platform. It provides a clean, model-based interface for REST API v2 and a real-time WebSocket client.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'delta_exchange'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ ## Basic Configuration
20
+
21
+ The gem needs to be configured with your API credentials. You can do this in an initializer (for Rails) or at the top of your script.
22
+
23
+ ```ruby
24
+ require 'delta_exchange'
25
+
26
+ DeltaExchange.configure do |config|
27
+ config.api_key = 'YOUR_API_KEY'
28
+ config.api_secret = 'YOUR_API_SECRET'
29
+ config.testnet = true # Use Delta Testnet for testing
30
+ end
31
+ ```
32
+
33
+ ## Quick Start Example
34
+
35
+ ```ruby
36
+ # 1. Initialize the client
37
+ client = DeltaExchange::Client.new
38
+
39
+ # 2. Fetch all products
40
+ products = client.products.all
41
+
42
+ # 3. Find a specific product (e.g., BTCUSD perpetual)
43
+ btc_perp = products.find { |p| p[:symbol] == 'BTCUSD' }
44
+ puts "Trading #{btc_perp[:symbol]} with ID: #{btc_perp[:id]}"
45
+
46
+ # 4. Check your balance
47
+ balances = client.wallet.balances
48
+ puts "Available USDT: #{balances.find { |b| b[:asset_symbol] == 'USDT' }[:available_balance]}"
49
+
50
+ # 5. Place a limit order
51
+ order = client.orders.create(
52
+ product_id: btc_perp[:id],
53
+ size: 10,
54
+ side: 'buy',
55
+ order_type: 'limit_order',
56
+ limit_price: '50000.0'
57
+ )
58
+ puts "Order placed! ID: #{order[:id]}"
59
+ ```
60
+
61
+ ## Next Steps
62
+
63
+ * [Authentication Details](./AUTHENTICATION.md)
64
+ * [REST API Guide](./REST_API_GUIDE.md)
65
+ * [WebSocket Guide](./WEBSOCKET_GUIDE.md)
66
+ * [Rails Integration](./RAILS_INTEGRATION.md)
67
+ * [Standalone Ruby Guide](./STANDALONE_RUBY_GUIDE.md)
@@ -0,0 +1,135 @@
1
+ # Rails Integration Guide
2
+
3
+ Integrating the DeltaExchange gem into a Rails application is simple.
4
+
5
+ ## Step 1: Add the Gem
6
+
7
+ Add the gem to your `Gemfile`:
8
+
9
+ ```ruby
10
+ gem 'delta_exchange'
11
+ ```
12
+
13
+ And run:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ ## Step 2: Configure with Initializer
20
+
21
+ Create `config/initializers/delta_exchange.rb`:
22
+
23
+ ```ruby
24
+ # frozen_string_literal: true
25
+
26
+ DeltaExchange.configure do |config|
27
+ config.api_key = Rails.application.credentials.dig(:delta, :api_key)
28
+ config.api_secret = Rails.application.credentials.dig(:delta, :api_secret)
29
+ config.testnet = Rails.env.development? || Rails.env.test?
30
+ end
31
+ ```
32
+
33
+ ## Step 3: Use in Models or Services
34
+
35
+ For best practices, wrap the client in a service class:
36
+
37
+ ```ruby
38
+ # app/services/trading_service.rb
39
+ class TradingService
40
+ def initialize
41
+ @client = DeltaExchange::Client.new
42
+ end
43
+
44
+ def place_btc_limit_order(price, size)
45
+ @client.orders.create(
46
+ product_id: 1, # BTCUSD
47
+ size: size,
48
+ side: 'buy',
49
+ order_type: 'limit_order',
50
+ limit_price: price.to_s
51
+ )
52
+ end
53
+ end
54
+ ```
55
+
56
+ ## Step 4: Background Jobs for WebSocket
57
+
58
+ Since WebSockets need a persistent connection, it's best to run them in a separate process. You can use a custom rake task or a background job (like Sidekiq) to manage the stream.
59
+
60
+ **Example Rake Task (`lib/tasks/trading.rake`):**
61
+
62
+ ```ruby
63
+ namespace :trading do
64
+ desc "Start the Delta Exchange WebSocket stream"
65
+ task stream: :environment do
66
+ ws = DeltaExchange::Websocket::Client.new
67
+
68
+ ws.on :message do |data|
69
+ # Handle live updates and maybe update your database
70
+ if data['type'] == 'v2/ticker'
71
+ MarketPrice.update_price(data['symbol'], data['last_price'])
72
+ end
73
+ end
74
+
75
+ ws.on :open do
76
+ puts "Market stream active..."
77
+ ws.subscribe([{ name: "v2/ticker", symbols: ["BTCUSD"] }])
78
+ end
79
+
80
+ ws.connect!
81
+
82
+ # Keep the task alive
83
+ loop { sleep 1 }
84
+ end
85
+ end
86
+ ```
87
+
88
+ ## Step 5: Real-time UI with ActionCable
89
+
90
+ You can broadcast the incoming WebSocket data from the Rake task to your frontend using Rails ActionCable:
91
+
92
+ ```ruby
93
+ # inside the rake task's :message block
94
+ ActionCable.server.broadcast('price_channel', { symbol: data['symbol'], price: data['last_price'] })
95
+ ```
96
+
97
+ ## Step 6: Caching Real-time Data (Redis/Rails Cache)
98
+
99
+ For high-frequency data like LTP (Last Traded Price), you typically want to store the latest value in a fast cache so that your controllers, models, or other background jobs can access it instantly without hitting the database.
100
+
101
+ ### Using Rails.cache
102
+
103
+ ```ruby
104
+ # inside the rake task's :message block
105
+ if data['type'] == 'v2/ticker'
106
+ Rails.cache.write("ltp:#{data['symbol']}", data['last_price'])
107
+ end
108
+
109
+ # accessing it anywhere else in Rails
110
+ ltp = Rails.cache.read("ltp:BTCUSD")
111
+ ```
112
+
113
+ ### Using Redis Directly (Recommended for Performance)
114
+
115
+ If you have a dedicated Redis instance for market data:
116
+
117
+ ```ruby
118
+ # inside the rake task's :message block
119
+ $redis.hset("delta:ltp", data['symbol'], data['last_price'])
120
+
121
+ # accessing it elsewhere
122
+ ltp = $redis.hget("delta:ltp", "BTCUSD")
123
+ ```
124
+
125
+ ### Pattern: Fetcher Helper
126
+
127
+ It's common to create a helper in your `MarketPrice` model or a specific service:
128
+
129
+ ```ruby
130
+ class MarketPrice
131
+ def self.ltp(symbol)
132
+ Rails.cache.read("ltp:#{symbol}") || DeltaExchange::Models::Ticker.find(symbol)&.last_price
133
+ end
134
+ end
135
+ ```