buda_api 1.0.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.
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Authenticated API usage example
5
+ #
6
+ # This example shows how to use the authenticated API endpoints for trading
7
+
8
+ require_relative "../lib/buda_api"
9
+ require "dotenv/load"
10
+
11
+ def main
12
+ puts "=== Buda API Ruby SDK - Authenticated API Example ==="
13
+ puts
14
+
15
+ # Load credentials from environment variables
16
+ api_key = ENV["BUDA_API_KEY"]
17
+ api_secret = ENV["BUDA_API_SECRET"]
18
+
19
+ if api_key.nil? || api_secret.nil?
20
+ puts "ERROR: Please set BUDA_API_KEY and BUDA_API_SECRET environment variables"
21
+ puts "You can create a .env file with:"
22
+ puts "BUDA_API_KEY=your_api_key_here"
23
+ puts "BUDA_API_SECRET=your_api_secret_here"
24
+ return
25
+ end
26
+
27
+ # Configure the SDK for testing (use staging environment if available)
28
+ BudaApi.configure do |config|
29
+ config.debug_mode = true
30
+ config.timeout = 60
31
+ # config.base_url = "https://staging.buda.com/api/v2/" # Uncomment for staging
32
+ end
33
+
34
+ # Create an authenticated client
35
+ client = BudaApi.authenticated_client(
36
+ api_key: api_key,
37
+ api_secret: api_secret
38
+ )
39
+
40
+ market_id = "BTC-CLP"
41
+
42
+ begin
43
+ # 1. Check account balances
44
+ puts "1. Checking account balances..."
45
+
46
+ ["BTC", "CLP"].each do |currency|
47
+ balance = client.balance(currency)
48
+ puts "#{currency} Balance:"
49
+ puts " Total: #{balance.amount}"
50
+ puts " Available: #{balance.available_amount}"
51
+ puts " Frozen: #{balance.frozen_amount}"
52
+ puts " Pending withdrawals: #{balance.pending_withdraw_amount}"
53
+ puts
54
+ end
55
+
56
+ # 2. Get balance events
57
+ puts "2. Getting recent balance events..."
58
+ events_result = client.balance_events(
59
+ currencies: ["BTC", "CLP"],
60
+ event_names: ["transaction", "deposit_confirm"],
61
+ page: 1,
62
+ per_page: 5
63
+ )
64
+
65
+ puts "Total events: #{events_result[:total_count]}"
66
+ puts "Events on this page: #{events_result[:events].length}"
67
+ puts
68
+
69
+ # 3. Get order history
70
+ puts "3. Getting order history for #{market_id}..."
71
+ orders_result = client.orders(market_id, page: 1, per_page: 10)
72
+
73
+ puts "Orders found: #{orders_result.count}"
74
+ puts "Current page: #{orders_result.meta.current_page}"
75
+ puts "Total pages: #{orders_result.meta.total_pages}"
76
+
77
+ if orders_result.count > 0
78
+ puts "\nRecent orders:"
79
+ orders_result.orders.first(3).each do |order|
80
+ puts " Order ##{order.id}: #{order.type} #{order.amount} at #{order.limit} (#{order.state})"
81
+ puts " Created: #{order.created_at}"
82
+ puts " Filled: #{order.filled_percentage}%"
83
+ end
84
+ end
85
+ puts
86
+
87
+ # 4. Get quotation before placing an order
88
+ puts "4. Getting quotation for a small test order..."
89
+ test_amount = 0.0001 # Very small amount for testing
90
+
91
+ quotation = client.quotation(market_id, "bid_given_size", test_amount)
92
+ puts "To buy #{test_amount} BTC:"
93
+ puts " You would pay: #{quotation.quote_balance_change}"
94
+ puts " Fee: #{quotation.fee}"
95
+ puts
96
+
97
+ # 5. Simulate a withdrawal
98
+ puts "5. Simulating a BTC withdrawal..."
99
+ begin
100
+ withdrawal_sim = client.simulate_withdrawal("BTC", 0.001)
101
+ puts "Withdrawal simulation:"
102
+ puts " Amount: #{withdrawal_sim.amount}"
103
+ puts " Fee: #{withdrawal_sim.fee}"
104
+ puts " Currency: #{withdrawal_sim.currency}"
105
+ puts " State: #{withdrawal_sim.state}"
106
+ rescue BudaApi::ApiError => e
107
+ puts "Could not simulate withdrawal: #{e.message}"
108
+ end
109
+ puts
110
+
111
+ # 6. Place a very small test order (BE CAREFUL!)
112
+ puts "6. DEMO: Placing a test order (this is for demonstration only)..."
113
+ puts "WARNING: This would place an actual order on the exchange!"
114
+ puts "Skipping order placement in this example for safety."
115
+
116
+ # UNCOMMENT THE FOLLOWING LINES ONLY IF YOU WANT TO PLACE ACTUAL ORDERS:
117
+ #
118
+ # begin
119
+ # # Place a limit buy order with a very low price (unlikely to fill)
120
+ # order = client.place_order(
121
+ # market_id,
122
+ # "Bid", # Buy order
123
+ # "limit", # Limit order
124
+ # 0.0001, # Very small amount
125
+ # 1000000 # Very low price (unlikely to execute)
126
+ # )
127
+ #
128
+ # puts "Order placed successfully:"
129
+ # puts " Order ID: #{order.id}"
130
+ # puts " Type: #{order.type}"
131
+ # puts " Amount: #{order.amount}"
132
+ # puts " Limit price: #{order.limit}"
133
+ # puts " State: #{order.state}"
134
+ # puts
135
+ #
136
+ # # Wait a moment then cancel the order
137
+ # puts "Cancelling the test order..."
138
+ # cancelled_order = client.cancel_order(order.id)
139
+ # puts "Order cancelled. New state: #{cancelled_order.state}"
140
+ #
141
+ # rescue BudaApi::ApiError => e
142
+ # puts "Could not place/cancel order: #{e.message}"
143
+ # end
144
+ puts
145
+
146
+ # 7. Get recent deposits and withdrawals
147
+ puts "7. Getting recent deposits and withdrawals..."
148
+
149
+ begin
150
+ withdrawals = client.withdrawals("BTC", page: 1, per_page: 3)
151
+ puts "Recent BTC withdrawals: #{withdrawals[:withdrawals].length}"
152
+ withdrawals[:withdrawals].each do |withdrawal|
153
+ puts " #{withdrawal.created_at.strftime('%Y-%m-%d')}: #{withdrawal.amount} (#{withdrawal.state})"
154
+ end
155
+
156
+ deposits = client.deposits("BTC", page: 1, per_page: 3)
157
+ puts "Recent BTC deposits: #{deposits[:deposits].length}"
158
+ deposits[:deposits].each do |deposit|
159
+ puts " #{deposit.created_at.strftime('%Y-%m-%d')}: #{deposit.amount} (#{deposit.state})"
160
+ end
161
+ rescue BudaApi::ApiError => e
162
+ puts "Could not fetch deposits/withdrawals: #{e.message}"
163
+ end
164
+ puts
165
+
166
+ # 8. Demonstrate batch operations
167
+ puts "8. DEMO: Batch operations (cancel multiple orders)"
168
+ puts "This would cancel multiple orders at once and optionally place new ones."
169
+ puts "Skipping for safety in this example."
170
+
171
+ # Example of batch operations:
172
+ # result = client.batch_orders(
173
+ # cancel_orders: [order_id_1, order_id_2],
174
+ # place_orders: [
175
+ # {
176
+ # type: "Bid",
177
+ # price_type: "limit",
178
+ # amount: "0.001",
179
+ # limit: "50000000"
180
+ # }
181
+ # ]
182
+ # )
183
+
184
+ rescue BudaApi::AuthenticationError => e
185
+ puts "Authentication Error: #{e.message}"
186
+ puts "Please check your API credentials"
187
+ rescue BudaApi::AuthorizationError => e
188
+ puts "Authorization Error: #{e.message}"
189
+ puts "Your API key may not have sufficient permissions"
190
+ rescue BudaApi::RateLimitError => e
191
+ puts "Rate Limit Error: #{e.message}"
192
+ puts "Please wait before making more requests"
193
+ rescue BudaApi::ApiError => e
194
+ puts "API Error: #{e.message}"
195
+ puts "Status code: #{e.status_code}" if e.status_code
196
+ puts "Response: #{e.response_body}" if e.response_body
197
+ rescue BudaApi::ValidationError => e
198
+ puts "Validation Error: #{e.message}"
199
+ rescue => e
200
+ puts "Unexpected Error: #{e.class.name} - #{e.message}"
201
+ end
202
+
203
+ puts
204
+ puts "=== Authenticated API example completed ==="
205
+ puts
206
+ puts "IMPORTANT NOTES:"
207
+ puts "- This example uses very small amounts and low prices for safety"
208
+ puts "- Always test on staging environment first if available"
209
+ puts "- Be careful when placing real orders on production"
210
+ puts "- Monitor your orders and cancel them if needed"
211
+ end
212
+
213
+ main if __FILE__ == $0
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Error handling and debugging example
5
+ #
6
+ # This example demonstrates comprehensive error handling and debugging features
7
+
8
+ require_relative "../lib/buda_api"
9
+
10
+ def main
11
+ puts "=== Buda API Ruby SDK - Error Handling & Debugging Example ==="
12
+ puts
13
+
14
+ # Configure SDK with debug mode enabled
15
+ BudaApi.configure do |config|
16
+ config.debug_mode = true
17
+ config.timeout = 10 # Short timeout to trigger timeout errors
18
+ config.logger_level = :debug
19
+ end
20
+
21
+ # Example 1: Connection and timeout errors
22
+ puts "1. Testing connection errors..."
23
+ begin
24
+ # Create client with invalid base URL
25
+ client = BudaApi::PublicClient.new(base_url: "https://invalid-domain-that-does-not-exist.com/api/v2/")
26
+ client.markets
27
+ rescue BudaApi::ConnectionError => e
28
+ puts "✅ Caught ConnectionError as expected: #{e.message}"
29
+ rescue => e
30
+ puts "❌ Unexpected error: #{e.class.name} - #{e.message}"
31
+ end
32
+ puts
33
+
34
+ # Example 2: Timeout errors
35
+ puts "2. Testing timeout handling..."
36
+ begin
37
+ client = BudaApi::PublicClient.new(timeout: 0.001) # Very short timeout
38
+ client.markets
39
+ rescue BudaApi::TimeoutError => e
40
+ puts "✅ Caught TimeoutError as expected: #{e.message}"
41
+ rescue BudaApi::ConnectionError => e
42
+ puts "✅ Connection error (may occur instead of timeout): #{e.message}"
43
+ rescue => e
44
+ puts "❌ Unexpected error: #{e.class.name} - #{e.message}"
45
+ end
46
+ puts
47
+
48
+ # Example 3: Validation errors
49
+ puts "3. Testing validation errors..."
50
+ client = BudaApi::PublicClient.new
51
+
52
+ begin
53
+ # Test invalid market ID
54
+ client.ticker("INVALID-MARKET")
55
+ rescue BudaApi::ValidationError => e
56
+ puts "✅ Caught ValidationError as expected: #{e.message}"
57
+ rescue BudaApi::NotFoundError => e
58
+ puts "✅ Caught NotFoundError (API-level validation): #{e.message}"
59
+ rescue => e
60
+ puts "❌ Unexpected error: #{e.class.name} - #{e.message}"
61
+ end
62
+
63
+ begin
64
+ # Test missing required parameters
65
+ client.quotation(nil, "bid_given_size", 0.1)
66
+ rescue BudaApi::ValidationError => e
67
+ puts "✅ Caught ValidationError for missing parameter: #{e.message}"
68
+ rescue => e
69
+ puts "❌ Unexpected error: #{e.class.name} - #{e.message}"
70
+ end
71
+ puts
72
+
73
+ # Example 4: Authentication errors
74
+ puts "4. Testing authentication errors..."
75
+ begin
76
+ auth_client = BudaApi::AuthenticatedClient.new(
77
+ api_key: "invalid_key",
78
+ api_secret: "invalid_secret"
79
+ )
80
+ auth_client.balance("BTC")
81
+ rescue BudaApi::AuthenticationError => e
82
+ puts "✅ Caught AuthenticationError as expected: #{e.message}"
83
+ puts " Status code: #{e.status_code}"
84
+ rescue => e
85
+ puts "❌ Unexpected error: #{e.class.name} - #{e.message}"
86
+ end
87
+ puts
88
+
89
+ # Example 5: API response errors
90
+ puts "5. Testing API response handling..."
91
+ begin
92
+ # Test with non-existent market (should return 404)
93
+ client.ticker("FAKE-COIN")
94
+ rescue BudaApi::NotFoundError => e
95
+ puts "✅ Caught NotFoundError as expected: #{e.message}"
96
+ puts " Status code: #{e.status_code}"
97
+ puts " Response headers: #{e.response_headers.keys.join(', ')}" if e.response_headers
98
+ rescue => e
99
+ puts "❌ Unexpected error: #{e.class.name} - #{e.message}"
100
+ end
101
+ puts
102
+
103
+ # Example 6: Rate limiting (simulated)
104
+ puts "6. Testing rate limit handling..."
105
+ puts "Making multiple rapid requests to potentially trigger rate limiting..."
106
+
107
+ 10.times do |i|
108
+ begin
109
+ client.ticker("BTC-CLP")
110
+ print "."
111
+ rescue BudaApi::RateLimitError => e
112
+ puts "\n✅ Caught RateLimitError: #{e.message}"
113
+ break
114
+ rescue => e
115
+ puts "\n❌ Unexpected error: #{e.class.name} - #{e.message}"
116
+ break
117
+ end
118
+
119
+ # Small delay between requests
120
+ sleep(0.1)
121
+ end
122
+ puts "\nCompleted rate limit test"
123
+ puts
124
+
125
+ # Example 7: Invalid credentials format
126
+ puts "7. Testing credential validation..."
127
+ begin
128
+ BudaApi::AuthenticatedClient.new(api_key: "", api_secret: "secret")
129
+ rescue BudaApi::ConfigurationError => e
130
+ puts "✅ Caught ConfigurationError for empty API key: #{e.message}"
131
+ rescue => e
132
+ puts "❌ Unexpected error: #{e.class.name} - #{e.message}"
133
+ end
134
+
135
+ begin
136
+ BudaApi::AuthenticatedClient.new(api_key: "key", api_secret: nil)
137
+ rescue BudaApi::ConfigurationError => e
138
+ puts "✅ Caught ConfigurationError for nil API secret: #{e.message}"
139
+ rescue => e
140
+ puts "❌ Unexpected error: #{e.class.name} - #{e.message}"
141
+ end
142
+ puts
143
+
144
+ # Example 8: Debugging successful requests
145
+ puts "8. Demonstrating debug output for successful requests..."
146
+ puts "Watch the detailed HTTP request/response logs above ☝️"
147
+
148
+ begin
149
+ markets = client.markets
150
+ puts "✅ Successfully fetched #{markets.length} markets with debug logging"
151
+
152
+ ticker = client.ticker("BTC-CLP")
153
+ puts "✅ Successfully fetched ticker with debug logging"
154
+
155
+ rescue => e
156
+ puts "❌ Unexpected error: #{e.class.name} - #{e.message}"
157
+ end
158
+ puts
159
+
160
+ # Example 9: Custom error context
161
+ puts "9. Demonstrating error context and logging..."
162
+
163
+ begin
164
+ # Simulate a custom error scenario
165
+ raise BudaApi::ValidationError, "Custom validation failed"
166
+ rescue BudaApi::ValidationError => e
167
+ BudaApi::Logger.log_error(e, context: {
168
+ user_action: "Testing custom error",
169
+ market_id: "BTC-CLP",
170
+ timestamp: Time.now
171
+ })
172
+ puts "✅ Logged custom error with context"
173
+ end
174
+ puts
175
+
176
+ # Example 10: Recovery strategies
177
+ puts "10. Demonstrating error recovery strategies..."
178
+
179
+ def retry_with_backoff(max_retries: 3, initial_delay: 1)
180
+ retries = 0
181
+
182
+ begin
183
+ yield
184
+ rescue BudaApi::RateLimitError, BudaApi::ServerError => e
185
+ retries += 1
186
+
187
+ if retries <= max_retries
188
+ delay = initial_delay * (2 ** (retries - 1))
189
+ puts "Retry #{retries}/#{max_retries} after #{delay}s due to: #{e.class.name}"
190
+ sleep(delay)
191
+ retry
192
+ else
193
+ puts "Max retries exceeded, giving up"
194
+ raise
195
+ end
196
+ end
197
+ end
198
+
199
+ begin
200
+ retry_with_backoff do
201
+ # This might fail due to rate limiting or server errors
202
+ client.markets
203
+ end
204
+ puts "✅ Request succeeded (possibly after retries)"
205
+ rescue => e
206
+ puts "❌ Request failed after retries: #{e.message}"
207
+ end
208
+
209
+ puts
210
+ puts "=== Error Handling & Debugging Example Completed ==="
211
+ puts
212
+ puts "Key takeaways:"
213
+ puts "- Always wrap API calls in appropriate exception handlers"
214
+ puts "- Use debug mode during development to see detailed HTTP logs"
215
+ puts "- Implement retry logic for transient errors (rate limits, server errors)"
216
+ puts "- Validate parameters client-side before making API calls"
217
+ puts "- Log errors with context for easier debugging"
218
+ puts "- Different error types require different handling strategies"
219
+ end
220
+
221
+ main if __FILE__ == $0
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Basic public API usage example
5
+ #
6
+ # This example shows how to use the public API endpoints that don't require authentication
7
+
8
+ require_relative "../lib/buda_api"
9
+
10
+ def main
11
+ puts "=== Buda API Ruby SDK - Public API Example ==="
12
+ puts
13
+
14
+ # Configure the SDK
15
+ BudaApi.configure do |config|
16
+ config.debug_mode = true # Enable debug logging
17
+ config.timeout = 60 # Increase timeout to 60 seconds
18
+ end
19
+
20
+ # Create a public client
21
+ client = BudaApi.public_client
22
+
23
+ begin
24
+ # 1. Get all available markets
25
+ puts "1. Fetching all available markets..."
26
+ markets = client.markets
27
+ puts "Found #{markets.length} markets:"
28
+
29
+ markets.first(5).each do |market|
30
+ puts " - #{market.id}: #{market.name} (#{market.base_currency}/#{market.quote_currency})"
31
+ puts " Minimum order: #{market.minimum_order_amount}"
32
+ end
33
+ puts " ... and #{markets.length - 5} more" if markets.length > 5
34
+ puts
35
+
36
+ # 2. Get specific market details
37
+ market_id = "BTC-CLP"
38
+ puts "2. Getting details for #{market_id}..."
39
+ market = client.market_details(market_id)
40
+ puts "Market: #{market.name}"
41
+ puts "Base currency: #{market.base_currency}"
42
+ puts "Quote currency: #{market.quote_currency}"
43
+ puts "Minimum order amount: #{market.minimum_order_amount}"
44
+ puts
45
+
46
+ # 3. Get ticker information
47
+ puts "3. Getting ticker for #{market_id}..."
48
+ ticker = client.ticker(market_id)
49
+ puts "Last price: #{ticker.last_price}"
50
+ puts "Min ask: #{ticker.min_ask}"
51
+ puts "Max bid: #{ticker.max_bid}"
52
+ puts "Volume (24h): #{ticker.volume}"
53
+ puts "Price change (24h): #{ticker.price_variation_24h}%"
54
+ puts "Price change (7d): #{ticker.price_variation_7d}%"
55
+ puts
56
+
57
+ # 4. Get order book
58
+ puts "4. Getting order book for #{market_id}..."
59
+ order_book = client.order_book(market_id)
60
+
61
+ puts "Best ask: #{order_book.best_ask.price} (#{order_book.best_ask.amount})"
62
+ puts "Best bid: #{order_book.best_bid.price} (#{order_book.best_bid.amount})"
63
+ puts "Spread: #{order_book.spread} (#{order_book.spread_percentage}%)"
64
+
65
+ puts "\nTop 3 asks:"
66
+ order_book.asks.first(3).each_with_index do |ask, i|
67
+ puts " #{i + 1}. #{ask.price} x #{ask.amount} = #{ask.total}"
68
+ end
69
+
70
+ puts "\nTop 3 bids:"
71
+ order_book.bids.first(3).each_with_index do |bid, i|
72
+ puts " #{i + 1}. #{bid.price} x #{bid.amount} = #{bid.total}"
73
+ end
74
+ puts
75
+
76
+ # 5. Get recent trades
77
+ puts "5. Getting recent trades for #{market_id}..."
78
+ trades = client.trades(market_id, limit: 5)
79
+
80
+ puts "Recent trades (#{trades.count} total):"
81
+ trades.each do |trade|
82
+ puts " #{trade.timestamp.strftime('%H:%M:%S')}: #{trade.amount} at #{trade.price} (#{trade.direction})"
83
+ end
84
+ puts
85
+
86
+ # 6. Get quotation
87
+ puts "6. Getting quotation for buying 0.001 BTC..."
88
+ quotation = client.quotation(market_id, "bid_given_size", 0.001)
89
+ puts "Quotation type: #{quotation.type}"
90
+ puts "Amount: #{quotation.amount}"
91
+ puts "You would pay: #{quotation.quote_balance_change}"
92
+ puts "Fee: #{quotation.fee}"
93
+ puts
94
+
95
+ # 7. Get market reports
96
+ puts "7. Getting average price report for the last 24 hours..."
97
+ start_time = Time.now - 86400 # 24 hours ago
98
+ avg_prices = client.average_prices_report(market_id, start_at: start_time)
99
+
100
+ if avg_prices.any?
101
+ puts "Average price data points: #{avg_prices.length}"
102
+ puts "First data point: #{avg_prices.first.average} at #{avg_prices.first.timestamp}"
103
+ puts "Last data point: #{avg_prices.last.average} at #{avg_prices.last.timestamp}"
104
+ else
105
+ puts "No average price data available for the specified period"
106
+ end
107
+ puts
108
+
109
+ puts "8. Getting candlestick report for the last 24 hours..."
110
+ candles = client.candlestick_report(market_id, start_at: start_time)
111
+
112
+ if candles.any?
113
+ puts "Candlestick data points: #{candles.length}"
114
+ last_candle = candles.last
115
+ puts "Last candle:"
116
+ puts " Time: #{last_candle.timestamp}"
117
+ puts " Open: #{last_candle.open}"
118
+ puts " High: #{last_candle.high}"
119
+ puts " Low: #{last_candle.low}"
120
+ puts " Close: #{last_candle.close}"
121
+ puts " Volume: #{last_candle.volume}"
122
+ else
123
+ puts "No candlestick data available for the specified period"
124
+ end
125
+
126
+ rescue BudaApi::ApiError => e
127
+ puts "API Error: #{e.message}"
128
+ puts "Status code: #{e.status_code}" if e.status_code
129
+ puts "Response: #{e.response_body}" if e.response_body
130
+ rescue BudaApi::ConnectionError => e
131
+ puts "Connection Error: #{e.message}"
132
+ rescue BudaApi::ValidationError => e
133
+ puts "Validation Error: #{e.message}"
134
+ rescue => e
135
+ puts "Unexpected Error: #{e.class.name} - #{e.message}"
136
+ end
137
+
138
+ puts
139
+ puts "=== Example completed ==="
140
+ end
141
+
142
+ main if __FILE__ == $0