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
@@ -0,0 +1,150 @@
1
+ # REST API Guide
2
+
3
+ DeltaExchange REST API v2 follows standard JSON patterns. The gem exposes resources through the `Client` object.
4
+
5
+ ## Initializing the Client
6
+
7
+ ```ruby
8
+ client = DeltaExchange::Client.new
9
+ ```
10
+
11
+ ## Resources
12
+
13
+ ### Products
14
+
15
+ Provides data about tradable instruments.
16
+
17
+ ```ruby
18
+ products = client.products.all
19
+ symbol_data = client.products.find('BTCUSD')
20
+ tickers = client.products.tickers
21
+ single_ticker = client.products.ticker('BTCUSD')
22
+ leverage_data = client.products.leverage(1) # For product_id: 1
23
+ client.products.set_leverage(1, leverage: "25")
24
+ ```
25
+
26
+ ### Orders
27
+
28
+ Execution management.
29
+
30
+ ```ruby
31
+ # Create a limit order
32
+ order = client.orders.create(
33
+ product_id: 1,
34
+ size: 10,
35
+ side: 'buy',
36
+ order_type: 'limit_order',
37
+ limit_price: '50000.0'
38
+ )
39
+
40
+ # Edit an order
41
+ client.orders.update(
42
+ id: order[:id],
43
+ product_id: 1,
44
+ size: 12,
45
+ limit_price: '50100.0'
46
+ )
47
+
48
+ # Cancel an order
49
+ client.orders.cancel(id: order[:id], product_id: 1)
50
+
51
+ # Cancel all orders
52
+ client.orders.cancel_all(product_id: 1) # Optional product filter
53
+
54
+ # Batch orders (up to 50 in one call)
55
+ client.orders.create_batch(
56
+ product_id: 1,
57
+ orders: [
58
+ { size: 5, side: 'buy', order_type: 'limit_order', limit_price: '49000.0' },
59
+ { size: 5, side: 'buy', order_type: 'limit_order', limit_price: '48000.0' }
60
+ ]
61
+ )
62
+ ```
63
+
64
+ ### Positions
65
+
66
+ Margin and leverage tracking.
67
+
68
+ ```ruby
69
+ # Fetch all active open positions (uses /v2/positions/margined internally)
70
+ positions = client.positions.margined
71
+
72
+ # Change leverage for an open position
73
+ client.positions.change_leverage(product_id: 1, leverage: "50")
74
+
75
+ # Adjust margin (add/remove)
76
+ client.positions.adjust_margin(product_id: 1, amount: "100.0", type: "add")
77
+
78
+ # Close all positions
79
+ client.positions.close_all
80
+ ```
81
+
82
+ ### Market Data
83
+
84
+ Historical and statistical information.
85
+
86
+ ```ruby
87
+ # Get order book (Level 2)
88
+ book = client.market_data.l2_orderbook('BTCUSD')
89
+
90
+ # Get recent trades
91
+ trades = client.market_data.trades('BTCUSD')
92
+
93
+ # Get candles (OHLCV)
94
+ candles = client.market_data.candles(
95
+ product_id: 1,
96
+ resolution: '1m',
97
+ start_time: (Time.now - 3600).to_i,
98
+ end_time: Time.now.to_i
99
+ )
100
+
101
+ # Get specialized data
102
+ funding = client.market_data.funding_rates(product_id: 1)
103
+ oi = client.market_data.open_interest(product_id: 1)
104
+ ```
105
+
106
+ ### Wallet
107
+
108
+ Account balances and history.
109
+
110
+ ```ruby
111
+ balances = client.wallet.balances
112
+ history = client.wallet.transactions
113
+ deposits = client.wallet.deposits
114
+ withdrawals = client.wallet.withdrawals
115
+
116
+ # Sub-account balance transfer
117
+ client.wallet.subaccount_transfer(
118
+ asset_id: 1, # USDT
119
+ amount: "500.0",
120
+ sub_account_id: 1234,
121
+ method: "deposit" # deposit into sub-account
122
+ )
123
+ ```
124
+
125
+ ### Account
126
+
127
+ User-level configuration and statistics.
128
+
129
+ ```ruby
130
+ profile = client.account.profile
131
+ fee_tiers = client.account.fee_tiers
132
+ referrals = client.account.referrals
133
+ client.account.update_trading_preferences(cancel_on_disconnect: true)
134
+ ```
135
+
136
+ ## Error Handling
137
+
138
+ Standardized API and validation errors.
139
+
140
+ ```ruby
141
+ begin
142
+ client.orders.create(size: 0) # This will fail validation
143
+ rescue DeltaExchange::ValidationError => e
144
+ puts "Check your inputs: #{e.message}"
145
+ rescue DeltaExchange::RateLimitError => e
146
+ puts "Slowing down! Retry after #{e.retry_after_seconds}s"
147
+ rescue DeltaExchange::ApiError => e
148
+ puts "API Error: #{e.message} (Code: #{e.code})"
149
+ end
150
+ ```
@@ -0,0 +1,73 @@
1
+ # Standalone Ruby Script Guide
2
+
3
+ The DeltaExchange gem can be used in any Ruby environment, from simple CLI scripts to powerful trading bots.
4
+
5
+ ## Script Structure
6
+
7
+ ```ruby
8
+ # frozen_string_literal: true
9
+
10
+ require 'bundler/inline'
11
+
12
+ # 1. Inline gem dependency (no need for a Gemfile)
13
+ gemfile do
14
+ source 'https://rubygems.org'
15
+ gem 'delta_exchange'
16
+ gem 'dotenv' # for loading credentials from .env
17
+ end
18
+
19
+ require 'delta_exchange'
20
+ require 'dotenv/load'
21
+
22
+ # 2. Configure the client
23
+ DeltaExchange.configure do |config|
24
+ config.api_key = ENV['DELTA_API_KEY']
25
+ config.api_secret = ENV['DELTA_API_SECRET']
26
+ config.testnet = true
27
+ end
28
+
29
+ # 3. Business logic
30
+ def run_trading_loop
31
+ client = DeltaExchange::Client.new
32
+
33
+ loop do
34
+ ticker = client.products.ticker('BTCUSD')
35
+ puts "BTC Price: #{ticker[:last_price]}"
36
+
37
+ # Place your automated trading strategy here...
38
+
39
+ sleep 10 # Wait 10 seconds before next check
40
+ end
41
+ rescue Interrupt
42
+ puts "\nStopping bot..."
43
+ end
44
+
45
+ run_trading_loop
46
+ ```
47
+
48
+ ## Running with `.env` file
49
+
50
+ Create a file named `.env` in the same directory as your script:
51
+
52
+ ```bash
53
+ DELTA_API_KEY=your_actual_key
54
+ DELTA_API_SECRET=your_actual_secret
55
+ DELTA_TESTNET=true
56
+ ```
57
+
58
+ ## Using as a CLI Tool
59
+
60
+ The gem includes a console for interactive use:
61
+
62
+ ```bash
63
+ # From the project root
64
+ bin/console
65
+ ```
66
+
67
+ Once inside, you can interact with the API directly:
68
+
69
+ ```ruby
70
+ irb(main):001> client = DeltaExchange::Client.new
71
+ irb(main):002> client.products.all.first[:symbol]
72
+ => "BTCUSD"
73
+ ```
@@ -0,0 +1,160 @@
1
+ # WebSocket Guide
2
+
3
+ DeltaExchange WebSocket API v2 provides real-time streaming for public market data and private user updates.
4
+
5
+ ## Basic Usage
6
+
7
+ The WebSocket client runs in a background thread using `EventMachine`.
8
+
9
+ ```ruby
10
+ ws = DeltaExchange::Websocket::Client.new
11
+
12
+ # Handle public updates
13
+ ws.on :message do |data|
14
+ case data['type']
15
+ when 'v2/ticker'
16
+ puts "Price update: #{data['symbol']} is now #{data['last_price']}"
17
+ when 'l2_updates'
18
+ puts "Orderbook update for #{data['symbol']}"
19
+ end
20
+ end
21
+
22
+ # Handle specific events
23
+ ws.on :open do
24
+ puts "WebSocket Connected!"
25
+
26
+ # Subscribe to channels
27
+ ws.subscribe([
28
+ { name: "v2/ticker", symbols: ["BTCUSD", "ETHUSD"] },
29
+ { name: "l2_updates", symbols: ["BTCUSD"] }
30
+ ])
31
+ end
32
+
33
+ ws.connect!
34
+
35
+ # Keep the main process alive (only needed for standalone scripts)
36
+ loop { sleep 1 }
37
+ ```
38
+
39
+ ## Private Channels
40
+
41
+ If you provide an `api_key` and `api_secret`, the gem automatically handles authentication upon connection.
42
+
43
+ ```ruby
44
+ # The gem will use global configuration if not passed explicitly
45
+ ws = DeltaExchange::Websocket::Client.new
46
+
47
+ ws.on :open do
48
+ # Authenticated! Now subscribe to private data
49
+ ws.subscribe([
50
+ { name: "orders" },
51
+ { name: "positions" },
52
+ { name: "margins" }
53
+ ])
54
+ end
55
+
56
+ ws.on :message do |data|
57
+ if data['type'] == 'orders'
58
+ puts "Order status changed! New status: #{data['status']}"
59
+ end
60
+ end
61
+
62
+ ws.connect!
63
+ ```
64
+
65
+ ## Available Channels
66
+
67
+ ### Public
68
+ - `v2/ticker`: Live price and 24h stats.
69
+ - `l1_orderbook`: Top of the book.
70
+ - `l2_orderbook`: Full order book (snapshot).
71
+ - `l2_updates`: Incremental order book updates.
72
+ - `all_trades`: Live public trade stream.
73
+ - `mark_price`: Current mark price for perpetuals.
74
+ - `candlesticks`: Live OHLCV candle updates.
75
+ - `spot_price`: Current index spot price.
76
+
77
+ ### Private (Auth Required)
78
+ - `orders`: Personal order fill and status updates.
79
+ - `positions`: Personal position change updates.
80
+ - `user_trades`: Personal execution stream.
81
+ - `margins`: Personal margin balance updates.
82
+
83
+ ## Performance Notes
84
+
85
+ * **EM Reactor**: The gem starts an EventMachine reactor in a background thread. This means it won't block your main application (like a Rails server).
86
+ * **JSON Parsing**: Every message is parsed into a Ruby Hash automatically.
87
+ * **Reconnection**: The gem includes internal logic to attempt reconnection if the socket drops.
88
+
89
+ ## Advanced: Persistence and Caching
90
+
91
+ In a production trading application, you often need to access the "Last Traded Price" (LTP) from different parts of your application (e.g., a Rails controller or a background job) without maintaining a constant WebSocket connection in every process.
92
+
93
+ The best practice is to use a centralized store like **Redis** or **Rails Cache**.
94
+
95
+ ### 1. Storing Ticks in Redis
96
+
97
+ Using Redis allows multiple processes to read the latest price instantly.
98
+
99
+ ```ruby
100
+ require 'redis'
101
+ redis = Redis.new
102
+
103
+ ws = DeltaExchange::Websocket::Client.new
104
+
105
+ ws.on :message do |data|
106
+ if data['type'] == 'v2/ticker'
107
+ symbol = data['symbol']
108
+ price = data['last_price']
109
+
110
+ # Store the latest price in Redis with an optional TTL
111
+ redis.set("delta:ltp:#{symbol}", price)
112
+
113
+ # Optionally store the full tick as JSON
114
+ redis.set("delta:tick:#{symbol}", data.to_json)
115
+ end
116
+ end
117
+
118
+ ws.connect!
119
+ ```
120
+
121
+ ### 2. Storing Ticks in Rails Cache
122
+
123
+ If you are using Rails, you can utilize the built-in cache (which often uses Redis as a backend).
124
+
125
+ ```ruby
126
+ # Inside your WebSocket worker/task
127
+ ws.on :message do |data|
128
+ if data['type'] == 'v2/ticker'
129
+ Rails.cache.write("delta_ltp_#{data['symbol']}", data['last_price'])
130
+ end
131
+ end
132
+ ```
133
+
134
+ ### 3. Accessing LTP from a Controller
135
+
136
+ Once stored, you can access the data from anywhere in your Rails app:
137
+
138
+ ```ruby
139
+ class TradesController < ApplicationController
140
+ def current_price
141
+ # Fast read from cache/redis
142
+ price = Rails.cache.read("delta_ltp_#{params[:symbol]}")
143
+
144
+ render json: { symbol: params[:symbol], price: price }
145
+ end
146
+ end
147
+ ```
148
+
149
+ ### 4. Background Job Pattern
150
+
151
+ For complex bots, use the WebSocket to trigger background jobs for execution:
152
+
153
+ ```ruby
154
+ ws.on :message do |data|
155
+ if data['type'] == 'v2/ticker' && data['last_price'].to_f > 60000.0
156
+ # Trigger a trade job if price threshold met
157
+ TradeExecutionJob.perform_later('BTCUSD', 'sell', data['last_price'])
158
+ end
159
+ end
160
+ ```
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "delta_exchange"
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+
5
+ module DeltaExchange
6
+ class Auth
7
+ def self.sign(method, timestamp, path, query_string, payload, secret)
8
+ prehash = "#{method.upcase}#{timestamp}#{path}#{query_string}#{payload}"
9
+ OpenSSL::HMAC.hexdigest("SHA256", secret, prehash)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "json"
5
+ require "time"
6
+ require "uri"
7
+ require "active_support/core_ext/hash/indifferent_access"
8
+ require "active_support/core_ext/object/blank"
9
+ require "active_support/core_ext/time"
10
+
11
+ module DeltaExchange
12
+ class Client
13
+ attr_reader :root_url, :connection
14
+
15
+ def initialize(api_key: nil, api_secret: nil, testnet: nil, base_url: nil)
16
+ DeltaExchange.ensure_configuration!
17
+ config = DeltaExchange.configuration
18
+ @api_key = api_key || config.api_key
19
+ @api_secret = api_secret || config.api_secret
20
+ @testnet = testnet.nil? ? config.testnet : testnet
21
+ @root_url = resolve_root_url(config, base_url)
22
+ @connection = build_connection(@root_url, config)
23
+ end
24
+
25
+ def rebuild_connection!
26
+ config = DeltaExchange.configuration
27
+ @connection = build_connection(@root_url, config)
28
+ end
29
+
30
+ def request(method, path, payload = {}, params = {}, authenticate: true)
31
+ ensure_credentials!(authenticate)
32
+ timestamp = Time.now.utc.to_i.to_s
33
+ query_string = params.empty? ? "" : "?#{URI.encode_www_form(params)}"
34
+ body = payload.empty? ? "" : payload.to_json
35
+
36
+ headers = {
37
+ "Content-Type" => "application/json",
38
+ "Accept" => "application/json",
39
+ "User-Agent" => DeltaExchange.configuration.user_agent
40
+ }
41
+
42
+ if authenticate
43
+ headers["api-key"] = @api_key
44
+ headers["timestamp"] = timestamp
45
+ headers["signature"] = Auth.sign(method, timestamp, path, query_string, body, @api_secret)
46
+ end
47
+
48
+ response = @connection.send(method) do |req|
49
+ req.url "#{path}#{query_string}"
50
+ req.headers.merge!(headers)
51
+ req.body = body unless body.empty?
52
+ end
53
+
54
+ handle_response(response)
55
+ rescue Faraday::TimeoutError, Faraday::ConnectionFailed, Faraday::SSLError => e
56
+ raise(NetworkError.new(e.message).tap { |err| err.set_backtrace(e.backtrace) })
57
+ rescue Faraday::Error => e
58
+ raise(NetworkError.new("Faraday error: #{e.message}").tap { |err| err.set_backtrace(e.backtrace) })
59
+ end
60
+
61
+ def get(path, params = {}, authenticate: true)
62
+ request(:get, path, {}, params, authenticate: authenticate)
63
+ end
64
+
65
+ def post(path, payload = {}, authenticate: true)
66
+ request(:post, path, payload, {}, authenticate: authenticate)
67
+ end
68
+
69
+ def put(path, payload = {}, authenticate: true)
70
+ request(:put, path, payload, {}, authenticate: authenticate)
71
+ end
72
+
73
+ def patch(path, payload = {}, authenticate: true)
74
+ request(:patch, path, payload, {}, authenticate: authenticate)
75
+ end
76
+
77
+ def delete(path, payload = {}, params = {}, authenticate: true)
78
+ request(:delete, path, payload, params, authenticate: authenticate)
79
+ end
80
+
81
+ def products
82
+ @products ||= Resources::Products.new(self)
83
+ end
84
+
85
+ def orders
86
+ @orders ||= Resources::Orders.new(self)
87
+ end
88
+
89
+ def positions
90
+ @positions ||= Resources::Positions.new(self)
91
+ end
92
+
93
+ def account
94
+ @account ||= Resources::Account.new(self)
95
+ end
96
+
97
+ def wallet
98
+ @wallet ||= Resources::Wallet.new(self)
99
+ end
100
+
101
+ def assets
102
+ @assets ||= Resources::Assets.new(self)
103
+ end
104
+
105
+ def indices
106
+ @indices ||= Resources::Indices.new(self)
107
+ end
108
+
109
+ def fills
110
+ @fills ||= Resources::Fills.new(self)
111
+ end
112
+
113
+ def market_data
114
+ @market_data ||= Resources::MarketData.new(self)
115
+ end
116
+
117
+ def heartbeat
118
+ @heartbeat ||= Resources::Heartbeat.new(self)
119
+ end
120
+
121
+ private
122
+
123
+ def ensure_credentials!(authenticate)
124
+ return unless authenticate
125
+
126
+ return if @api_key.present? && @api_secret.present?
127
+
128
+ raise DeltaExchange::AuthenticationError, "api_key and api_secret are required for authenticated requests"
129
+ end
130
+
131
+ def resolve_root_url(config, explicit_base_url)
132
+ return explicit_base_url if explicit_base_url.present?
133
+
134
+ base = config.instance_variable_get(:@base_url)
135
+ return base if base.present?
136
+
137
+ @testnet ? DeltaExchange::Configuration::TESTNET_URL : DeltaExchange::Configuration::PRODUCTION_URL
138
+ end
139
+
140
+ def build_connection(url, config)
141
+ Faraday.new(url: url) do |f|
142
+ f.request :url_encoded
143
+ if ENV["DELTA_DEBUG"] == "true"
144
+ f.response :logger, DeltaExchange.logger, headers: { redact: ["api-key", "signature"] }, bodies: false
145
+ end
146
+ f.options.timeout = config.read_timeout
147
+ f.options.open_timeout = config.connect_timeout
148
+ f.options.write_timeout = config.write_timeout if f.options.respond_to?(:write_timeout=)
149
+ f.adapter Faraday.default_adapter
150
+ end
151
+ end
152
+
153
+ def handle_response(response)
154
+ body_str = response.body.to_s
155
+
156
+ if response.status == 429
157
+ retry_after = response.headers["X-RATE-LIMIT-RESET"]&.to_i
158
+ raise DeltaExchange::RateLimitError.new(
159
+ "Rate limited",
160
+ retry_after_seconds: retry_after,
161
+ response_body: parse_json_optional(body_str)
162
+ )
163
+ end
164
+
165
+ if body_str.blank?
166
+ raise DeltaExchange::Error, "API returned empty body (HTTP #{response.status})" unless response.success?
167
+
168
+ return {}.with_indifferent_access
169
+ end
170
+
171
+ parsed_response = JSON.parse(body_str).with_indifferent_access
172
+
173
+ return parsed_response if http_ok_without_api_failure?(response, parsed_response)
174
+
175
+ raise DeltaExchange::ApiError.from_hash(parsed_response, status: response.status)
176
+ rescue JSON::ParserError
177
+ raise DeltaExchange::Error, "API returned non-JSON response (HTTP #{response.status}): #{body_str[0, 500]}"
178
+ end
179
+
180
+ def parse_json_optional(raw)
181
+ return {}.with_indifferent_access if raw.blank?
182
+
183
+ JSON.parse(raw).with_indifferent_access
184
+ rescue JSON::ParserError
185
+ { "raw" => raw }.with_indifferent_access
186
+ end
187
+
188
+ def http_ok_without_api_failure?(response, parsed_response)
189
+ return false unless response.success?
190
+
191
+ return parsed_response[:success] != false if parsed_response.key?(:success)
192
+
193
+ true
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeltaExchange
4
+ class Configuration
5
+ PRODUCTION_URL = Constants::Urls::REST_PRODUCTION
6
+ TESTNET_URL = Constants::Urls::REST_TESTNET
7
+ DEFAULT_CONNECT_TIMEOUT = 10
8
+ DEFAULT_READ_TIMEOUT = 30
9
+ DEFAULT_WRITE_TIMEOUT = 30
10
+
11
+ attr_accessor :api_key, :api_secret, :testnet, :connect_timeout, :read_timeout, :write_timeout, :user_agent, :websocket_reconnect_delay, :time_zone, :auto_retry_rate_limit
12
+
13
+ # When set, used as the REST base URL instead of {PRODUCTION_URL} / {TESTNET_URL}.
14
+ attr_writer :base_url
15
+
16
+ def initialize
17
+ @api_key = ENV.fetch("DELTA_API_KEY", nil)
18
+ @api_secret = ENV.fetch("DELTA_API_SECRET", nil)
19
+ @testnet = ENV.fetch("DELTA_TESTNET", "false").to_s.casecmp("true").zero?
20
+ @base_url = nil
21
+ @connect_timeout = ENV.fetch("DELTA_CONNECT_TIMEOUT", DEFAULT_CONNECT_TIMEOUT).to_i
22
+ @read_timeout = ENV.fetch("DELTA_READ_TIMEOUT", DEFAULT_READ_TIMEOUT).to_i
23
+ @write_timeout = ENV.fetch("DELTA_WRITE_TIMEOUT", DEFAULT_WRITE_TIMEOUT).to_i
24
+ @user_agent = ENV.fetch("DELTA_USER_AGENT", "delta-exchange-ruby")
25
+ @websocket_reconnect_delay = ENV.fetch("DELTA_WS_RECONNECT_DELAY", 5).to_i
26
+ @time_zone = ENV.fetch("DELTA_TIME_ZONE", "UTC")
27
+ @auto_retry_rate_limit = ENV.fetch("DELTA_AUTO_RETRY_RATE_LIMIT", "false").to_s.casecmp("true").zero?
28
+ end
29
+
30
+ def base_url
31
+ return @base_url if @base_url
32
+
33
+ testnet? ? TESTNET_URL : PRODUCTION_URL
34
+ end
35
+
36
+ def testnet?
37
+ @testnet == true
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeltaExchange
4
+ module Constants
5
+ module Urls
6
+ REST_PRODUCTION = "https://api.india.delta.exchange"
7
+ REST_TESTNET = "https://cdn-ind.testnet.deltaex.org"
8
+ WEBSOCKET_PRODUCTION = "wss://socket.india.delta.exchange"
9
+ WEBSOCKET_TESTNET = "wss://socket.testnet.deltaex.org"
10
+ end
11
+
12
+ module ContractType
13
+ PERPETUAL_FUTURES = "perpetual_futures"
14
+ CALL_OPTIONS = "call_options"
15
+ PUT_OPTIONS = "put_options"
16
+ MOVE_OPTIONS = "move_options"
17
+ SPREADS = "spreads"
18
+ FUTURES = "futures"
19
+
20
+ ALL = [PERPETUAL_FUTURES, CALL_OPTIONS, PUT_OPTIONS, MOVE_OPTIONS, SPREADS, FUTURES].freeze
21
+ end
22
+
23
+ module OrderType
24
+ LIMIT = "limit_order"
25
+ MARKET = "market_order"
26
+ STOP_LIMIT = "stop_limit_order"
27
+ STOP_MARKET = "stop_market_order"
28
+
29
+ ALL = [LIMIT, MARKET, STOP_LIMIT, STOP_MARKET].freeze
30
+ end
31
+
32
+ module Side
33
+ BUY = "buy"
34
+ SELL = "sell"
35
+
36
+ ALL = [BUY, SELL].freeze
37
+ end
38
+
39
+ module TimeInForce
40
+ GTC = "gtc"
41
+ IOC = "ioc"
42
+ FOK = "fok"
43
+
44
+ ALL = [GTC, IOC, FOK].freeze
45
+ end
46
+
47
+ module ProductState
48
+ UPCOMING = "upcoming"
49
+ LIVE = "live"
50
+ EXPIRED = "expired"
51
+ SETTLED = "settled"
52
+
53
+ ALL = [UPCOMING, LIVE, EXPIRED, SETTLED].freeze
54
+ end
55
+
56
+ module OrderState
57
+ OPEN = "open"
58
+ PENDING = "pending"
59
+ CLOSED = "closed"
60
+ CANCELLED = "cancelled"
61
+
62
+ ALL = [OPEN, PENDING, CLOSED, CANCELLED].freeze
63
+ end
64
+
65
+ module MarginMode
66
+ CROSS = "cross"
67
+ ISOLATED = "isolated"
68
+
69
+ ALL = [CROSS, ISOLATED].freeze
70
+ end
71
+ end
72
+ end