honeymaker 0.12.4-aarch64-linux

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 (136) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/native-gems.yml +100 -0
  3. data/.github/workflows/release.yml +36 -0
  4. data/.github/workflows/test.yml +33 -0
  5. data/LICENSE +21 -0
  6. data/README.md +219 -0
  7. data/Rakefile +78 -0
  8. data/crates/honeymaker/tests/vectors/decimal.json +146 -0
  9. data/crates/honeymaker/tests/vectors/kraken_add_order_wire.json +74 -0
  10. data/crates/honeymaker/tests/vectors/kraken_signing.json +3314 -0
  11. data/crates/honeymaker/tests/vectors/kraken_trades_pager.json +1583 -0
  12. data/lib/honeymaker/3.4/honeymaker_native.so +0 -0
  13. data/lib/honeymaker/4.0/honeymaker_native.so +0 -0
  14. data/lib/honeymaker/client.rb +139 -0
  15. data/lib/honeymaker/clients/binance.rb +687 -0
  16. data/lib/honeymaker/clients/binance_us.rb +42 -0
  17. data/lib/honeymaker/clients/bingx.rb +242 -0
  18. data/lib/honeymaker/clients/bitget.rb +318 -0
  19. data/lib/honeymaker/clients/bitrue.rb +245 -0
  20. data/lib/honeymaker/clients/bitvavo.rb +244 -0
  21. data/lib/honeymaker/clients/bybit.rb +308 -0
  22. data/lib/honeymaker/clients/coinbase.rb +326 -0
  23. data/lib/honeymaker/clients/gemini.rb +189 -0
  24. data/lib/honeymaker/clients/hyperliquid.rb +232 -0
  25. data/lib/honeymaker/clients/kraken.rb +379 -0
  26. data/lib/honeymaker/clients/kraken_futures.rb +78 -0
  27. data/lib/honeymaker/clients/kucoin.rb +310 -0
  28. data/lib/honeymaker/clients/mexc.rb +249 -0
  29. data/lib/honeymaker/exchange.rb +129 -0
  30. data/lib/honeymaker/exchanges/binance.rb +55 -0
  31. data/lib/honeymaker/exchanges/binance_us.rb +9 -0
  32. data/lib/honeymaker/exchanges/bingx.rb +56 -0
  33. data/lib/honeymaker/exchanges/bitget.rb +52 -0
  34. data/lib/honeymaker/exchanges/bitrue.rb +53 -0
  35. data/lib/honeymaker/exchanges/bitvavo.rb +65 -0
  36. data/lib/honeymaker/exchanges/bybit.rb +57 -0
  37. data/lib/honeymaker/exchanges/coinbase.rb +69 -0
  38. data/lib/honeymaker/exchanges/gemini.rb +134 -0
  39. data/lib/honeymaker/exchanges/hyperliquid.rb +67 -0
  40. data/lib/honeymaker/exchanges/kraken.rb +122 -0
  41. data/lib/honeymaker/exchanges/kucoin.rb +52 -0
  42. data/lib/honeymaker/exchanges/mexc.rb +56 -0
  43. data/lib/honeymaker/native/kraken.rb +263 -0
  44. data/lib/honeymaker/native.rb +42 -0
  45. data/lib/honeymaker/result.rb +46 -0
  46. data/lib/honeymaker/utils.rb +39 -0
  47. data/lib/honeymaker/version.rb +5 -0
  48. data/lib/honeymaker.rb +97 -0
  49. data/script/parity/kraken_client_live.rb +191 -0
  50. data/script/parity/kraken_live.rb +70 -0
  51. data/script/parity/kraken_transport.rb +604 -0
  52. data/script/parity/resolve.c +49 -0
  53. data/script/release/push_gems.sh +28 -0
  54. data/script/vectors/kraken.rb +50 -0
  55. data/script/vectors/kraken_stage2.rb +146 -0
  56. data/sig/honeymaker.rbs +4 -0
  57. data/test/fixtures/binance_book_ticker.json +7 -0
  58. data/test/fixtures/binance_exchange_info.json +30 -0
  59. data/test/fixtures/bingx_symbols.json +26 -0
  60. data/test/fixtures/bingx_ticker.json +12 -0
  61. data/test/fixtures/bitget_symbols.json +28 -0
  62. data/test/fixtures/bitget_tickers.json +14 -0
  63. data/test/fixtures/bitmart_symbols.json +26 -0
  64. data/test/fixtures/bitmart_ticker.json +12 -0
  65. data/test/fixtures/bitrue_book_ticker.json +7 -0
  66. data/test/fixtures/bitrue_exchange_info.json +34 -0
  67. data/test/fixtures/bitvavo_book_ticker.json +7 -0
  68. data/test/fixtures/bitvavo_markets.json +30 -0
  69. data/test/fixtures/bybit_instruments.json +23 -0
  70. data/test/fixtures/bybit_tickers.json +19 -0
  71. data/test/fixtures/coinbase_product.json +7 -0
  72. data/test/fixtures/coinbase_products.json +24 -0
  73. data/test/fixtures/gemini_pubticker.json +10 -0
  74. data/test/fixtures/gemini_symbol_detail.json +10 -0
  75. data/test/fixtures/gemini_symbols.json +1 -0
  76. data/test/fixtures/hyperliquid_all_mids.json +5 -0
  77. data/test/fixtures/hyperliquid_spot_meta.json +12 -0
  78. data/test/fixtures/kraken_asset_pairs.json +43 -0
  79. data/test/fixtures/kraken_ticker.json +16 -0
  80. data/test/fixtures/kucoin_orderbook_level1.json +10 -0
  81. data/test/fixtures/kucoin_symbols.json +17 -0
  82. data/test/fixtures/mexc_book_ticker.json +7 -0
  83. data/test/fixtures/mexc_exchange_info.json +64 -0
  84. data/test/honeymaker/client_test.rb +90 -0
  85. data/test/honeymaker/clients/binance_client_test.rb +151 -0
  86. data/test/honeymaker/clients/binance_us_client_test.rb +25 -0
  87. data/test/honeymaker/clients/bingx_client_test.rb +106 -0
  88. data/test/honeymaker/clients/bitget_client_test.rb +146 -0
  89. data/test/honeymaker/clients/bitrue_client_test.rb +69 -0
  90. data/test/honeymaker/clients/bitvavo_client_test.rb +156 -0
  91. data/test/honeymaker/clients/bybit_client_test.rb +137 -0
  92. data/test/honeymaker/clients/coinbase_client_test.rb +153 -0
  93. data/test/honeymaker/clients/gemini_client_test.rb +100 -0
  94. data/test/honeymaker/clients/honeymaker_client_registry_test.rb +39 -0
  95. data/test/honeymaker/clients/hyperliquid_client_test.rb +292 -0
  96. data/test/honeymaker/clients/kraken_client_test.rb +255 -0
  97. data/test/honeymaker/clients/kraken_futures_client_test.rb +54 -0
  98. data/test/honeymaker/clients/kucoin_client_test.rb +149 -0
  99. data/test/honeymaker/clients/mexc_client_test.rb +98 -0
  100. data/test/honeymaker/clients/validation_test.rb +167 -0
  101. data/test/honeymaker/error_chain_test.rb +133 -0
  102. data/test/honeymaker/exchange_test.rb +138 -0
  103. data/test/honeymaker/exchanges/binance_test.rb +83 -0
  104. data/test/honeymaker/exchanges/binance_us_test.rb +53 -0
  105. data/test/honeymaker/exchanges/bingx_test.rb +65 -0
  106. data/test/honeymaker/exchanges/bitget_test.rb +65 -0
  107. data/test/honeymaker/exchanges/bitrue_test.rb +65 -0
  108. data/test/honeymaker/exchanges/bitvavo_test.rb +65 -0
  109. data/test/honeymaker/exchanges/bybit_test.rb +55 -0
  110. data/test/honeymaker/exchanges/coinbase_test.rb +106 -0
  111. data/test/honeymaker/exchanges/gemini_catalogue_test.rb +118 -0
  112. data/test/honeymaker/exchanges/gemini_test.rb +184 -0
  113. data/test/honeymaker/exchanges/hyperliquid_test.rb +64 -0
  114. data/test/honeymaker/exchanges/kraken_test.rb +191 -0
  115. data/test/honeymaker/exchanges/kucoin_test.rb +55 -0
  116. data/test/honeymaker/exchanges/mexc_test.rb +97 -0
  117. data/test/honeymaker/honeymaker_test.rb +27 -0
  118. data/test/honeymaker/result_test.rb +42 -0
  119. data/test/honeymaker/utils_test.rb +64 -0
  120. data/test/native/backend_switch_test.rb +53 -0
  121. data/test/native/convert_test.rb +137 -0
  122. data/test/native/gem_isolation_test.rb +17 -0
  123. data/test/native/loader_test.rb +29 -0
  124. data/test/native/lockstep_test.rb +23 -0
  125. data/test/native/signing_smoke_test.rb +28 -0
  126. data/test/parity/kraken_client_parity_test.rb +398 -0
  127. data/test/parity/kraken_exchange_parity_test.rb +172 -0
  128. data/test/release/branch_hardening_test.rb +34 -0
  129. data/test/release/push_gems_test.rb +79 -0
  130. data/test/smoke.rb +24 -0
  131. data/test/support/fixture_helper.rb +13 -0
  132. data/test/support/kraken_signing_smoke.rb +21 -0
  133. data/test/support/parity_helper.rb +62 -0
  134. data/test/support/venue_double.rb +100 -0
  135. data/test/test_helper.rb +9 -0
  136. metadata +254 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ce03d589763a1ce403d35622db819a32dfa54b6ac86c3fd19941ecb3083a82ff
4
+ data.tar.gz: 2eef626eca2a9c2ff52e74c3f9b8695f6af426f62d6122331c77241319123f5c
5
+ SHA512:
6
+ metadata.gz: a3b24b61eaa393c7e7db0a4e30b20d34bafad08aca60961e04480c8efb016b27800555f862a0078857eb69a2cd61e4e69119a372d13480eca34dcba2dff431a0
7
+ data.tar.gz: a843783dd90df321366ed0c4b35232f66f4a0b44dd0dddb7fb46eababd92eb678219ad57f8814dea50b6f3df7e44aa6f430dd49fea1fca2a62c8c5214a817105
@@ -0,0 +1,100 @@
1
+ name: Native gems
2
+
3
+ on:
4
+ pull_request:
5
+ paths: ["crates/**", "ext/**", "Cargo.*", "rust-toolchain.toml", "honeymaker.gemspec", "Rakefile",
6
+ "lib/honeymaker/native.rb", "test/smoke.rb", ".github/workflows/native-gems.yml"]
7
+ workflow_call:
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ cross:
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ platform: [x86_64-linux, aarch64-linux, x86_64-darwin, arm64-darwin, x64-mingw-ucrt]
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
22
+ - uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
23
+ with:
24
+ ruby-version: "3.4"
25
+ bundler-cache: true
26
+ - uses: oxidize-rb/actions/cross-gem@ec90b4aa48795518d79be3f5cc478d1d7ccd02a8 # v1.5.0
27
+ id: cross
28
+ with:
29
+ platform: ${{ matrix.platform }}
30
+ ruby-versions: "3.4,4.0"
31
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
32
+ with:
33
+ name: gem-${{ matrix.platform }}
34
+ path: ${{ steps.cross.outputs.gem-path }}
35
+
36
+ source:
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
40
+ - uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
41
+ with:
42
+ ruby-version: "3.4"
43
+ bundler-cache: true
44
+ - run: bundle exec rake build
45
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
46
+ with:
47
+ name: gem-ruby
48
+ path: pkg/honeymaker-*.gem
49
+
50
+ source-install:
51
+ needs: source
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
55
+ - uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
56
+ with:
57
+ ruby-version: "4.0"
58
+ - run: rustup toolchain install 1.94.0 --profile minimal
59
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
60
+ with:
61
+ name: gem-ruby
62
+ path: gems
63
+ - run: gem install --no-document --platform ruby gems/*.gem
64
+ env:
65
+ RUSTUP_TOOLCHAIN: "1.94.0"
66
+ - run: ruby test/smoke.rb
67
+ env:
68
+ EXPECT_PLATFORM: ruby
69
+
70
+ smoke:
71
+ needs: cross
72
+ strategy:
73
+ fail-fast: false
74
+ matrix:
75
+ include:
76
+ - { os: ubuntu-latest, platform: x86_64-linux, ruby: "3.4" }
77
+ - { os: ubuntu-latest, platform: x86_64-linux, ruby: "4.0" }
78
+ - { os: ubuntu-24.04-arm, platform: aarch64-linux, ruby: "3.4" }
79
+ - { os: ubuntu-24.04-arm, platform: aarch64-linux, ruby: "4.0" }
80
+ - { os: macos-15-intel, platform: x86_64-darwin, ruby: "3.4" }
81
+ - { os: macos-15-intel, platform: x86_64-darwin, ruby: "4.0" }
82
+ - { os: macos-14, platform: arm64-darwin, ruby: "3.4" }
83
+ - { os: macos-14, platform: arm64-darwin, ruby: "4.0" }
84
+ - { os: windows-latest, platform: x64-mingw-ucrt, ruby: "3.4" }
85
+ - { os: windows-latest, platform: x64-mingw-ucrt, ruby: "4.0" }
86
+ runs-on: ${{ matrix.os }}
87
+ steps:
88
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
89
+ - uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
90
+ with:
91
+ ruby-version: ${{ matrix.ruby }}
92
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
93
+ with:
94
+ name: gem-${{ matrix.platform }}
95
+ path: gems
96
+ - run: gem install --no-document gems/*.gem
97
+ shell: bash
98
+ - run: ruby test/smoke.rb
99
+ env:
100
+ EXPECT_PLATFORM: ${{ matrix.platform }}
@@ -0,0 +1,36 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ gems:
12
+ uses: ./.github/workflows/native-gems.yml
13
+
14
+ publish:
15
+ needs: gems
16
+ runs-on: ubuntu-latest
17
+ environment: rubygems # required reviewer: Jan
18
+ permissions:
19
+ id-token: write
20
+ contents: read
21
+ steps:
22
+ # Checkout cleans the workspace, so it must precede artifact download.
23
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
24
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
25
+ with:
26
+ pattern: gem-*
27
+ merge-multiple: true
28
+ path: gems
29
+ - uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
30
+ with:
31
+ ruby-version: "3.4"
32
+ - uses: rubygems/configure-rubygems-credentials@bc6dd217f8a4f919d6835fcfefd470ef821f5c44 # v1.0.0
33
+ with:
34
+ trusted-publisher: true
35
+ - name: Push platform gems first, the source gem last (idempotent)
36
+ run: script/release/push_gems.sh gems "${GITHUB_REF_NAME#v}"
@@ -0,0 +1,33 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ os: [ubuntu-latest, macos-14]
18
+ ruby: ["3.4", "4.0"]
19
+ runs-on: ${{ matrix.os }}
20
+ steps:
21
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
22
+ - uses: oxidize-rb/actions/setup-ruby-and-rust@ec90b4aa48795518d79be3f5cc478d1d7ccd02a8 # v1.5.0
23
+ with:
24
+ ruby-version: ${{ matrix.ruby }}
25
+ bundler-cache: true
26
+ cargo-cache: true
27
+ - run: cargo test --locked -p honeymaker
28
+ - run: cargo test --locked -p honeymaker-client
29
+ - run: cargo clippy --locked -p honeymaker-client --all-targets -- -D warnings
30
+ - run: bundle exec rake compile
31
+ - run: bundle exec rake test
32
+ env:
33
+ HONEYMAKER_REQUIRE_NATIVE: "1"
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Deltabadger
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # Honeymaker
2
+
3
+ [![Gem Version](https://img.shields.io/gem/v/honeymaker)](https://rubygems.org/gems/honeymaker)
4
+ [![CI](https://github.com/deltabadger/honeymaker/actions/workflows/test.yml/badge.svg)](https://github.com/deltabadger/honeymaker/actions)
5
+ [![License](https://img.shields.io/github/license/deltabadger/honeymaker)](LICENSE)
6
+
7
+ Ruby clients for cryptocurrency exchange APIs used by [Deltabadger](https://github.com/deltabadger/deltabadger).
8
+
9
+ ## Supported Exchanges
10
+
11
+ Binance, Binance US, Kraken, Kraken Futures, Coinbase, Bybit, KuCoin, Bitget, MEXC, Bitvavo, Gemini, Hyperliquid, BingX, Bitrue.
12
+
13
+ ## Installation
14
+
15
+ ```ruby
16
+ gem "honeymaker"
17
+ ```
18
+
19
+ ## Native extension
20
+
21
+ Prebuilt native gems support Ruby 3.4 and 4.0 on `x86_64-linux`, `aarch64-linux`,
22
+ `x86_64-darwin`, `arm64-darwin`, and `x64-mingw-ucrt`. A source gem is also published.
23
+ Building from source needs Rust 1.94; in a checkout, run `bundle install` followed by
24
+ `bundle exec rake compile`.
25
+
26
+ The Ruby backend remains the default. Set `HONEYMAKER_NATIVE=kraken` before requiring
27
+ `honeymaker` to enable the Rust backend for Kraken. `HONEYMAKER_NATIVE` accepts a
28
+ comma-separated list of exchange names; Kraken is currently the supported native backend.
29
+ Other exchanges continue to use Ruby. Unset the variable to return to the Ruby backend.
30
+
31
+ ### Releases
32
+
33
+ Run `bundle exec rake release` for a patch release, `bundle exec rake release:minor`
34
+ for a minor release, or `bundle exec rake release:major` for a major release. The task
35
+ bumps the gem and Cargo workspace versions together, updates both lockfiles, compiles,
36
+ tests, commits the four version/lock files, and pushes the commit and a `v<version>` tag.
37
+ `bundle exec rake _tag_release` resumes the push without another version bump.
38
+
39
+ The tag triggers `.github/workflows/release.yml`, which calls the native-gem workflow
40
+ to build and smoke-test all five platform gems and the source gem. Configure the
41
+ GitHub `rubygems` environment with Jan as its required reviewer and configure RubyGems
42
+ trusted publishing for this repository's `release.yml` workflow and `rubygems` environment.
43
+ After Jan approves, CI publishes using trusted publishing, with platform gems first
44
+ and the source gem last.
45
+
46
+ Recovery:
47
+
48
+ - **Publish failed partway:** open Actions → the same workflow run → **Re-run failed jobs**.
49
+ The artifacts are retained, and the push loop skips gems already published with an
50
+ identical checksum. It stops on any mismatch; never override that.
51
+ - **Workflow cancelled or never finished building:** choose **Re-run all jobs** on the
52
+ tag's run. `gh workflow run` is not a substitute, because it isn't a tag-push event.
53
+ - **Bump commit pushed but tag push failed:** run
54
+ `git tag -a v<version> -m v<version> && git push origin v<version>`.
55
+ `_tag_release` is a no-op once the tag exists locally. If the tag already exists locally,
56
+ retry just `git push origin v<version>`.
57
+
58
+ ## Usage
59
+
60
+ ### Market Data
61
+
62
+ ```ruby
63
+ require "honeymaker"
64
+
65
+ exchange = Honeymaker.exchange("binance")
66
+ result = exchange.get_tickers_info
67
+
68
+ if result.success?
69
+ result.data.each do |ticker|
70
+ puts "#{ticker[:ticker]} — min: #{ticker[:minimum_quote_size]}, decimals: #{ticker[:base_decimals]}"
71
+ end
72
+ end
73
+ ```
74
+
75
+ ### Balances
76
+
77
+ ```ruby
78
+ client = Honeymaker.client("binance", api_key: "...", api_secret: "...")
79
+ result = client.get_balances
80
+
81
+ if result.success?
82
+ result.data.each do |symbol, balance|
83
+ puts "#{symbol}: free=#{balance[:free]}, locked=#{balance[:locked]}"
84
+ end
85
+ end
86
+ # => { "BTC" => { free: BigDecimal("0.5"), locked: BigDecimal("0.1") }, ... }
87
+ ```
88
+
89
+ Coinbase auto-resolves the default portfolio, or pass one explicitly:
90
+
91
+ ```ruby
92
+ client.get_balances(portfolio_uuid: "...")
93
+ ```
94
+
95
+ ### Placing Orders
96
+
97
+ Order placement returns a normalized `{ order_id:, raw: }` hash:
98
+
99
+ ```ruby
100
+ client = Honeymaker.client("binance", api_key: "...", api_secret: "...")
101
+
102
+ result = client.new_order(symbol: "BTCUSDT", side: "BUY", type: "MARKET", quote_order_qty: "100")
103
+ if result.success?
104
+ puts result.data[:order_id] # => "BTCUSDT-123456"
105
+ puts result.data[:raw] # full exchange response
106
+ end
107
+ ```
108
+
109
+ Method names vary by exchange (`new_order`, `create_order`, `add_order`, `place_order`, `submit_order`) but the return format is the same.
110
+
111
+ ### Querying Orders
112
+
113
+ Order queries return a normalized hash with unified status, amounts, and the raw response:
114
+
115
+ ```ruby
116
+ result = client.query_order(symbol: "BTCUSDT", order_id: 123456)
117
+ if result.success?
118
+ order = result.data
119
+ order[:order_id] # => "BTCUSDT-123456"
120
+ order[:status] # => :open, :closed, :cancelled, :failed, :unknown
121
+ order[:side] # => :buy, :sell
122
+ order[:order_type] # => :market, :limit
123
+ order[:price] # => BigDecimal — avg fill price
124
+ order[:amount] # => BigDecimal — requested base qty (nil if quote-denominated)
125
+ order[:quote_amount] # => BigDecimal — requested quote qty (nil if base-denominated)
126
+ order[:amount_exec] # => BigDecimal — filled base qty
127
+ order[:quote_amount_exec] # => BigDecimal — filled quote qty
128
+ order[:raw] # => Hash — full exchange response
129
+ end
130
+ ```
131
+
132
+ ### Account History (Tax Reporting)
133
+
134
+ History endpoints for margin, futures, staking/earn, and other tax-relevant events:
135
+
136
+ ```ruby
137
+ # Margin
138
+ client.margin_borrow_repay_history(type: "BORROW") # Binance
139
+ client.margin_interest_history # Binance, KuCoin, Bitget
140
+ client.margin_force_liquidation # Binance
141
+
142
+ # Futures
143
+ client.futures_income_history(income_type: "REALIZED_PNL") # Binance USDT-M
144
+ client.coin_futures_income_history # Binance Coin-M
145
+ client.futures_account_bills(product_type: "USDT-FUTURES") # Bitget
146
+ client.futures_income # BingX
147
+
148
+ # Staking / Earn
149
+ client.simple_earn_flexible_rewards # Binance
150
+ client.simple_earn_locked_subscriptions # Binance
151
+ client.earn_yield_history # Bybit
152
+ client.staking_rewards # Gemini
153
+ client.staking_rewards_history # Binance US
154
+
155
+ # Other
156
+ client.universal_transfer_history(type: "MAIN_MARGIN") # Binance
157
+ client.dust_log # Binance
158
+ client.asset_dividend # Binance
159
+ ```
160
+
161
+ Coverage varies by exchange. Kraken's `get_ledgers(type:)` covers margin, staking, and trades in a single endpoint. Coinbase's `list_transactions` covers 30+ event types.
162
+
163
+ ### Kraken Futures
164
+
165
+ Kraken Futures uses separate API keys and a different auth scheme — it's a standalone client:
166
+
167
+ ```ruby
168
+ client = Honeymaker.client("kraken_futures", api_key: "...", api_secret: "...")
169
+
170
+ client.get_accounts # wallet balances, margin, PnL
171
+ client.get_fills # trade fills
172
+ client.get_open_positions # open positions
173
+ client.historical_funding_rates(symbol: "PF_XBTUSD") # funding rate history
174
+ ```
175
+
176
+ ### Credential Validation
177
+
178
+ ```ruby
179
+ client = Honeymaker.client("binance", api_key: "...", api_secret: "...")
180
+ result = client.validate(:trading)
181
+ result.success? # => true if credentials have trading permissions
182
+ ```
183
+
184
+ ### Rate Limits
185
+
186
+ Each exchange exposes rate limit metadata (milliseconds between requests):
187
+
188
+ ```ruby
189
+ Honeymaker::Clients::Binance.rate_limits
190
+ # => { default: 100, orders: 200 }
191
+
192
+ Honeymaker::Clients::Kraken.rate_limits
193
+ # => { default: 1000, orders: 1000 }
194
+ ```
195
+
196
+ ### Proxy Support
197
+
198
+ ```ruby
199
+ client = Honeymaker.client("binance",
200
+ api_key: "...", api_secret: "...",
201
+ proxy: "http://proxy:8100"
202
+ )
203
+ ```
204
+
205
+ ## Result Objects
206
+
207
+ All methods return `Result::Success` or `Result::Failure`:
208
+
209
+ ```ruby
210
+ result = client.get_balances
211
+ result.success? # true/false
212
+ result.failure? # true/false
213
+ result.data # response payload
214
+ result.errors # array of error messages (empty on success)
215
+ ```
216
+
217
+ ## License
218
+
219
+ MIT
data/Rakefile ADDED
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rake/testtask"
4
+
5
+ if ENV["HONEYMAKER_RAKEFILE_LIB_ONLY"] != "1" && File.exist?(File.join(__dir__, "honeymaker.gemspec"))
6
+ require "bundler/gem_tasks"
7
+ require "rb_sys/extensiontask"
8
+
9
+ GEMSPEC = Gem::Specification.load(File.join(__dir__, "honeymaker.gemspec"))
10
+ RbSys::ExtensionTask.new("honeymaker_native", GEMSPEC) do |ext|
11
+ ext.lib_dir = "lib/honeymaker"
12
+ # Core-only edits must rebuild the extension too (the default pattern covers ext/ only).
13
+ ext.source_pattern = "{**/*,../../crates/honeymaker/**/*,../../Cargo}.{rs,toml,lock}"
14
+ ext.cross_compile = true
15
+ ext.cross_platform = %w[x86_64-linux aarch64-linux x86_64-darwin arm64-darwin x64-mingw-ucrt]
16
+ end
17
+ end
18
+
19
+ Rake::TestTask.new(:test) do |t|
20
+ t.libs << "test"
21
+ t.libs << "lib"
22
+ t.test_files = FileList["test/**/*_test.rb"]
23
+ end
24
+
25
+ task default: %i[compile test]
26
+
27
+ VERSION_FILE = "lib/honeymaker/version.rb"
28
+
29
+ def current_version
30
+ File.read(VERSION_FILE).match(/VERSION = "(.+)"/)[1]
31
+ end
32
+
33
+ def bump_version(segment)
34
+ major, minor, patch = current_version.split(".").map(&:to_i)
35
+ new_version = case segment
36
+ when :major then [major + 1, 0, 0]
37
+ when :minor then [major, minor + 1, 0]
38
+ when :patch then [major, minor, patch + 1]
39
+ end.join(".")
40
+ content = File.read(VERSION_FILE)
41
+ File.write(VERSION_FILE, content.sub(/VERSION = ".+"/, "VERSION = \"#{new_version}\""))
42
+ File.write("Cargo.toml", File.read("Cargo.toml").sub(/(\[workspace\.package\][^\[]*?^version = )"[^"]+"/m, "\\1\"#{new_version}\""))
43
+ puts "Bumped version to #{new_version}"
44
+ end
45
+
46
+ if ENV["HONEYMAKER_RAKEFILE_LIB_ONLY"] != "1" && File.exist?(File.join(__dir__, "honeymaker.gemspec"))
47
+ Rake::Task[:release].clear
48
+ end
49
+
50
+ def do_release(segment)
51
+ bump_version(segment)
52
+ sh "bundle install"
53
+ sh "cargo update --workspace --offline"
54
+ Rake::Task[:compile].invoke
55
+ Rake::Task[:test].invoke
56
+ sh %(git add #{VERSION_FILE} Cargo.toml Cargo.lock Gemfile.lock && git commit -m "v#{current_version}")
57
+ sh "bundle exec rake _tag_release"
58
+ end
59
+
60
+ # Pushes the bump commit and the v* tag; .github/workflows/release.yml builds and publishes.
61
+ task _tag_release: %w[release:guard_clean release:source_control_push]
62
+
63
+ desc "Bump patch, compile, test, and push a release tag for CI"
64
+ task :release do
65
+ do_release(:patch)
66
+ end
67
+
68
+ namespace :release do
69
+ desc "Bump minor, compile, test, and push a release tag for CI"
70
+ task :minor do
71
+ do_release(:minor)
72
+ end
73
+
74
+ desc "Bump major, compile, test, and push a release tag for CI"
75
+ task :major do
76
+ do_release(:major)
77
+ end
78
+ end
@@ -0,0 +1,146 @@
1
+ [
2
+ {
3
+ "input": "0.5",
4
+ "ok": true,
5
+ "finite": true,
6
+ "plain": "0.5",
7
+ "sign": 2
8
+ },
9
+ {
10
+ "input": "1",
11
+ "ok": true,
12
+ "finite": true,
13
+ "plain": "1.0",
14
+ "sign": 2
15
+ },
16
+ {
17
+ "input": "-0",
18
+ "ok": true,
19
+ "finite": true,
20
+ "plain": "-0.0",
21
+ "sign": -1
22
+ },
23
+ {
24
+ "input": "-0.0000",
25
+ "ok": true,
26
+ "finite": true,
27
+ "plain": "-0.0",
28
+ "sign": -1
29
+ },
30
+ {
31
+ "input": "0.0000000001",
32
+ "ok": true,
33
+ "finite": true,
34
+ "plain": "0.0000000001",
35
+ "sign": 2
36
+ },
37
+ {
38
+ "input": "123456789012345678901234567890.123456789",
39
+ "ok": true,
40
+ "finite": true,
41
+ "plain": "123456789012345678901234567890.123456789",
42
+ "sign": 2
43
+ },
44
+ {
45
+ "input": "1e-9",
46
+ "ok": true,
47
+ "finite": true,
48
+ "plain": "0.000000001",
49
+ "sign": 2
50
+ },
51
+ {
52
+ "input": "1E5",
53
+ "ok": true,
54
+ "finite": true,
55
+ "plain": "100000.0",
56
+ "sign": 2
57
+ },
58
+ {
59
+ "input": " 1.5 ",
60
+ "ok": true,
61
+ "finite": true,
62
+ "plain": "1.5",
63
+ "sign": 2
64
+ },
65
+ {
66
+ "input": "1_000.5",
67
+ "ok": true,
68
+ "finite": true,
69
+ "plain": "1000.5",
70
+ "sign": 2
71
+ },
72
+ {
73
+ "input": ".5",
74
+ "ok": true,
75
+ "finite": true,
76
+ "plain": "0.5",
77
+ "sign": 2
78
+ },
79
+ {
80
+ "input": "5.",
81
+ "ok": true,
82
+ "finite": true,
83
+ "plain": "5.0",
84
+ "sign": 2
85
+ },
86
+ {
87
+ "input": "+2",
88
+ "ok": true,
89
+ "finite": true,
90
+ "plain": "2.0",
91
+ "sign": 2
92
+ },
93
+ {
94
+ "input": "",
95
+ "ok": false,
96
+ "error": "invalid value for BigDecimal(): \"\""
97
+ },
98
+ {
99
+ "input": "abc",
100
+ "ok": false,
101
+ "error": "invalid value for BigDecimal(): \"abc\""
102
+ },
103
+ {
104
+ "input": "1,5",
105
+ "ok": false,
106
+ "error": "invalid value for BigDecimal(): \"1,5\""
107
+ },
108
+ {
109
+ "input": "0x10",
110
+ "ok": false,
111
+ "error": "invalid value for BigDecimal(): \"0x10\""
112
+ },
113
+ {
114
+ "input": "NaN",
115
+ "ok": true,
116
+ "finite": false,
117
+ "plain": "NaN",
118
+ "sign": 0
119
+ },
120
+ {
121
+ "input": "Infinity",
122
+ "ok": true,
123
+ "finite": false,
124
+ "plain": "Infinity",
125
+ "sign": 3
126
+ },
127
+ {
128
+ "input": "-Infinity",
129
+ "ok": true,
130
+ "finite": false,
131
+ "plain": "-Infinity",
132
+ "sign": -3
133
+ },
134
+ {
135
+ "input": "1d2",
136
+ "ok": true,
137
+ "finite": true,
138
+ "plain": "100.0",
139
+ "sign": 2
140
+ },
141
+ {
142
+ "input": "true",
143
+ "ok": false,
144
+ "error": "invalid value for BigDecimal(): \"true\""
145
+ }
146
+ ]