├── .github └── workflows │ └── bandit.yml ├── .gitignore ├── .pylintrc ├── LICENSE ├── README.md ├── example.py ├── examples └── trading_bot │ ├── backtesting.ipynb │ ├── bot.py │ ├── bot_utils.py │ ├── config.py │ ├── requirements.txt │ └── result.pdf ├── hftcryptoapi ├── __init__.py ├── bitmart │ ├── Bitmart.py │ ├── CHANGELOG.md │ ├── CONDUCT.md │ ├── CONTRIBUTING.md │ ├── __init__.py │ ├── api_client.py │ ├── bitmart_errors.py │ ├── bitmart_utils.py │ ├── bm_logging.py │ ├── data │ │ ├── __init__.py │ │ ├── constants.py │ │ ├── rest.py │ │ └── ws.py │ ├── docs │ │ ├── Makefile │ │ ├── build │ │ │ ├── doctrees │ │ │ │ ├── bitmart.doctree │ │ │ │ ├── environment.pickle │ │ │ │ ├── index.doctree │ │ │ │ └── modules.doctree │ │ │ └── html │ │ │ │ ├── .buildinfo │ │ │ │ ├── _sources │ │ │ │ ├── bitmart.rst.txt │ │ │ │ ├── index.rst.txt │ │ │ │ └── modules.rst.txt │ │ │ │ ├── _static │ │ │ │ ├── _sphinx_javascript_frameworks_compat.js │ │ │ │ ├── alabaster.css │ │ │ │ ├── basic.css │ │ │ │ ├── custom.css │ │ │ │ ├── doctools.js │ │ │ │ ├── documentation_options.js │ │ │ │ ├── file.png │ │ │ │ ├── jquery-3.6.0.js │ │ │ │ ├── jquery.js │ │ │ │ ├── language_data.js │ │ │ │ ├── minus.png │ │ │ │ ├── plus.png │ │ │ │ ├── pygments.css │ │ │ │ ├── searchtools.js │ │ │ │ ├── sphinx_highlight.js │ │ │ │ ├── underscore-1.13.1.js │ │ │ │ └── underscore.js │ │ │ │ ├── bitmart.html │ │ │ │ ├── genindex.html │ │ │ │ ├── index.html │ │ │ │ ├── modules.html │ │ │ │ ├── objects.inv │ │ │ │ ├── search.html │ │ │ │ └── searchindex.js │ │ ├── make.bat │ │ └── source │ │ │ ├── bitmart.rst │ │ │ ├── conf.py │ │ │ ├── index.rst │ │ │ └── modules.rst │ ├── exceptions.py │ └── ws_base.py └── data │ ├── __init__.py │ ├── historical │ ├── __init__.py │ └── utils.py │ └── live │ └── __init__.py ├── pyproject.toml ├── requirements.txt ├── setup.py └── tests └── __init__.py /.github/workflows/bandit.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # Bandit is a security linter designed to find common security issues in Python code. 7 | # This action will run Bandit on your codebase. 8 | # The results of the scan will be found under the Security tab of your repository. 9 | 10 | # https://github.com/marketplace/actions/bandit-scan is ISC licensed, by abirismyname 11 | # https://pypi.org/project/bandit/ is Apache v2.0 licensed, by PyCQA 12 | 13 | name: Bandit 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '20 4 * * 6' 22 | 23 | jobs: 24 | bandit: 25 | permissions: 26 | contents: read # for actions/checkout to fetch code 27 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results 28 | actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status 29 | 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v2 33 | - name: Bandit Scan 34 | uses: shundor/python-bandit-scan@9cc5aa4a006482b8a7f91134412df6772dbda22c 35 | with: # optional arguments 36 | # exit with 0, even with results found 37 | exit_zero: true # optional, default is DEFAULT 38 | # Github token of the repository (automatically created by Github) 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information. 40 | # File or directory to run bandit on 41 | # path: # optional, default is . 42 | # Report only issues of a given severity level or higher. Can be LOW, MEDIUM or HIGH. Default is UNDEFINED (everything) 43 | # level: # optional, default is UNDEFINED 44 | # Report only issues of a given confidence level or higher. Can be LOW, MEDIUM or HIGH. Default is UNDEFINED (everything) 45 | # confidence: # optional, default is UNDEFINED 46 | # comma-separated list of paths (glob patterns supported) to exclude from scan (note that these are in addition to the excluded paths provided in the config file) (default: .svn,CVS,.bzr,.hg,.git,__pycache__,.tox,.eggs,*.egg) 47 | # excluded_paths: # optional, default is DEFAULT 48 | # comma-separated list of test IDs to skip 49 | # skips: # optional, default is DEFAULT 50 | # path to a .bandit file that supplies command line arguments 51 | # ini_path: # optional, default is DEFAULT 52 | 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.pyc 3 | venv 4 | venv2 5 | dist 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/LICENSE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HFT CRYPTO API-BitMart 2 | 3 | Python module for Bitmart SDK 4 | Watch video -> https://www.youtube.com/watch?v=OKxEWVpEWSI 5 | 6 | ## Installation 7 | 8 | ``` pip install hftcryptoapi``` 9 | 10 | # Spot Market 11 | 12 | ## Introduction 13 | 14 | ``` from hftcryptoapi.bitmart import Bitmart ``` 15 | 16 | ## Basic Information 17 | 18 | Initialise an instance of Bitmart client: 19 | 20 | ``` 21 | from hftcryptoapi.bitmart import Bitmart 22 | 23 | api_key = "" 24 | secret_key = "" 25 | memo = "" 26 | 27 | client = Bitmart(api_key, secret_key, memo, exchange=Exchange.BITMART) 28 | ``` 29 | 30 | ## System Status 31 | 32 | - Get System Time, returns system time in datetime format. 33 | 34 | ``` 35 | bt_time = client.get_system_time() 36 | ``` 37 | 38 | - Get System Service Status, returns system status 39 | 40 | ``` 41 | bt_staus = client.get_service_status() 42 | ``` 43 | 44 | ## Public Market Data 45 | 46 | Functions to get info from spot market public API. 47 | 48 | - Get Currency List 49 | 50 | ``` 51 | currency_list = client.get_currency_list() 52 | ``` 53 | 54 | - Get List of Trading Pairs, return a list of all trading pairs 55 | 56 | ``` 57 | trading_pairs = client.get_list_of_trading_pairs() 58 | ``` 59 | 60 | - Get List of Spot Symbol Details 61 | 62 | ``` 63 | symbols_details = client.get_spot_symbols_details() 64 | ``` 65 | 66 | - Get Ticker details by Symbol 67 | 68 | ``` 69 | symbol_details = client.get_spot_ticker_details("BTC_USDT") 70 | ``` 71 | 72 | - Get K-Line, return Kline object for specified symbol and time period for SPOT and FUTURES markets 73 | 74 | ``` 75 | symbol_klines = client.get_symbol_kline(symbol, fromTime, toTime, step, market = Market.SPOT) 76 | ``` 77 | 78 | - Get Depth 79 | Returns [buys], [sells] wrapped in SportDepth or FuturesDepth object, depends on market type (Market.SPOT or 80 | Market.FUTURES) 81 | 82 | ``` 83 | symbol_depth = client.get_symbol_depth(symbol, precision, size, market=Market.SPOT) 84 | ``` 85 | 86 | - Get Recent Trades, returns Trade object for specified symbol and number of trades (by default: 50) 87 | 88 | ``` 89 | bt_trades = client.get_symbol_recent_trades(symbol, N) 90 | ``` 91 | 92 | ## Funding Account Data 93 | 94 | - Get Account Balance, a unified method for all types of markets (SPOT, MARGIN, FUTURES). Market should be defined. 95 | Returns list of currencies/positions with attributes unique for each market: 96 | 97 | ``` 98 | result = client.get_account_balance(market=Market.FUTURES) 99 | result = client.get_account_balance(market=Market.SPOT_MARGIN) 100 | [print(b) for b in client.get_account_balance(market=Market.SPOT).items] 101 | ``` 102 | 103 | - Get User Fee Rate 104 | 105 | ``` 106 | fee_rate = client.get_spot_user_fee_rate() 107 | ``` 108 | 109 | - Get Actual Trade Fee Rate 110 | 111 | ``` 112 | bt_trade_fee = client.get_trade_fee_rate(symbol) 113 | ``` 114 | 115 | ## Spot/Margin Trading 116 | 117 | - Place Spot Order (V2) 118 | 119 | ``` 120 | order = client.submit_order(market=Market.SPOT, symbol=symbol, side=SpotSide.BUY, size=0.1, price=70) 121 | ``` 122 | 123 | - Place Margin Order 124 | 125 | ``` 126 | order = client.submit_order(market=Market.SPOT_MARGIN, symbol=symbol, side=SpotSide.BUY, size=0.1, price=70) 127 | ``` 128 | 129 | - Cancel an Order (V3) 130 | 131 | ``` 132 | client.cancel_order(order) 133 | # OR 134 | client.cancel_order_by_id(order.symbol, order_id=order.order_id, market=Market.SPOT) 135 | 136 | ``` 137 | 138 | - Cancel All Orders 139 | 140 | ``` 141 | client.cancel_all_orders(symbol=symbol_spot, market=Market.SPOT, side=SpotSide.BUY) 142 | ``` 143 | 144 | - Get Order Detail (V2), get/update order details 145 | 146 | ``` 147 | order = get_order_details(symbol, order_id, market) 148 | order = client.update_order_details(order) 149 | ``` 150 | 151 | - Get User Order History (V3), return list of order objects 152 | 153 | ``` 154 | history = client.get_order_history(symbol=symbol_eth, market=Market.SPOT) 155 | ``` 156 | 157 | ### Margin Loan 158 | 159 | - Get Trading Pair Borrowing Rate and Amount 160 | 161 | ``` 162 | rate = client.spot_margin_borrowing_rate(symbol_spot) 163 | ``` 164 | 165 | - Get Borrow Record(Isolated) 166 | 167 | ``` 168 | b_records = client.spot_margin_get_borrow_record(symbol_spot) 169 | ``` 170 | 171 | - Get Repayment Record(Isolated) 172 | 173 | ``` 174 | r_records = client.spot_margin_get_repay_record(symbol_spot) 175 | ``` 176 | 177 | - Margin Borrow (Isolated) 178 | 179 | ``` 180 | borrow_id = client.spot_margin_borrow(symbol_spot, "BTC", 0.005) 181 | ``` 182 | 183 | - Margin Repay (Isolated) 184 | 185 | ``` 186 | repay_id = client.spot_margin_repay(symbol_spot, "BTC", 0.005) 187 | ``` 188 | 189 | # Futures 190 | 191 | ## Basic Information 192 | 193 | To access methods for Futures account/market methods should have a flag Market.FUTURES passed to. 194 | 195 | ## Futures Market Data 196 | 197 | - Get Futures Open Interest 198 | 199 | ``` 200 | futures_open_interest = client.get_futures_open_interest(symbol) 201 | ``` 202 | 203 | - Get Current Funding Rate for futures 204 | 205 | ``` 206 | funding_rate = client.get_futures_funding_rate(symbol) 207 | ``` 208 | 209 | - Get List of Futures Contract Details 210 | 211 | ``` 212 | contracts_details = client.get_futures_contracts_details() 213 | ``` 214 | 215 | ## Futures Trading 216 | 217 | - Get Futures Position details for a specified contract 218 | 219 | ``` 220 | client.get_futures_position_details(symbol) 221 | ``` 222 | 223 | - Close Futures Position 224 | 225 | ``` 226 | client.close_futures_position(symbol=symbol, position_side=Position.SHORT, open_type=OrderOpenType.CROSS) 227 | ``` 228 | 229 | - Get Account Balance - see spot description 230 | 231 | - Submit Order - see spot description 232 | 233 | - Cancel Order - see spot description 234 | 235 | - Cancel All orders - see spot description 236 | 237 | - Get Order Detail - see spot description 238 | 239 | - Get Order History - see spot description 240 | 241 | ## WebSockets 242 | 243 | - Subscribe to one or many WebSocket events 244 | 245 | ``` 246 | # SPOT 247 | client.subscribe_public(Market.SPOT, [BtSpotSocketKlineChannels.K_LINE_CHANNEL_1HOUR, 248 | BtSpotSocketDepthChannels.DEPTH_CHANNEL_5LEVEL, 249 | BtSpotTradeChannel, 250 | BtSpotTickerChannel], 251 | symbols=[symbol_spot]) 252 | client.subscribe_private(Market.SPOT, [BtSpotOrderChannel], symbols=[symbol_spot]) 253 | 254 | # FUTURES 255 | client.subscribe_public(Market.FUTURES, [BtFuturesTickerChannel]) 256 | client.subscribe_public(Market.FUTURES, [BtFuturesSocketKlineChannels.K_LINE_CHANNEL_1HOUR, 257 | BtFuturesSocketDepthChannels.DEPTH_CHANNEL_5LEVEL], [symbol]) 258 | client.subscribe_private(Market.FUTURES, [BtFuturesTPrivatePositionChannel]) 259 | client.subscribe_private(Market.FUTURES, [BtFuturesTPrivateAssetChannel], ['ETH', 'USDT']) 260 | ``` 261 | 262 | - Unsubscribe from one or many WebSocket events 263 | 264 | ``` 265 | client.unsubscribe_private(Market.FUTURES, [BtFuturesTPrivatePositionChannel]) 266 | client.unsubscribe_private(Market.FUTURES, [BtFuturesSocketDepthChannels], [symbol]) 267 | ``` 268 | 269 | - Start WebSocket listener for market type 270 | 271 | ``` 272 | def _on_message(self, msg: Union[WebSocketKline, WebSocketPositionFutures]): 273 | if type(msg) is WebSocketKline: 274 | # ... 275 | else: 276 | # .. 277 | client.start_websockets(market=Market.FUTURES, on_message=_on_message) 278 | client.start_websockets(Market.SPOT, on_message=_on_message_spot)) 279 | ``` 280 | 281 | - Stop and disconnect from WebSockets 282 | 283 | ``` 284 | client.stop_websockets(Market.FUTURES) 285 | ``` 286 | 287 | # ChangeLog 288 | 289 | 20.12.2022 Version 1.0.6 - Margin Loan implementation 290 | 291 | 19.12.2022 Version 1.0.5 292 | -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | import os 2 | from datetime import datetime, timedelta 3 | from time import sleep 4 | 5 | from hftcryptoapi.bitmart import Bitmart 6 | from hftcryptoapi.bitmart.data.constants import * 7 | 8 | if __name__ == "__main__": 9 | api_key = os.getenv("API_KEY") 10 | secret_key = os.getenv("SECRET_KEY") 11 | memo = os.getenv("MEMO") 12 | 13 | to_time = datetime.now() 14 | from_time = to_time - timedelta(days=10) 15 | symbol = "BTCUSDT" 16 | symbol_spot = "BTC_USDT" 17 | symbol_eth = "ETHUSDT" 18 | client = Bitmart.BitmartClient(api_key, secret_key, memo) 19 | # GENERAL PUBLIC 20 | bt_status = client.get_service_status() 21 | items = client.get_system_time() 22 | currency_list = client.get_currency_list() 23 | trading_pairs = client.get_list_of_trading_pairs() 24 | symbols_details = client.get_spot_symbols_details() 25 | contracts_details = client.get_futures_contracts_details() 26 | symbol_details = client.get_spot_ticker_details(symbol_spot) 27 | kline_steps = client.get_kline_steps() # Not used 28 | 29 | btc_usdt_klines = client.get_symbol_kline( 30 | symbol="BTC_USDT", 31 | tf=TimeFrame.tf_1h, 32 | market=Market.SPOT, 33 | from_time=from_time, 34 | to_time=to_time, 35 | ) 36 | for kline in btc_usdt_klines: 37 | print(str(kline)) 38 | 39 | symbol_klines = client.get_symbol_kline( 40 | symbol=symbol, 41 | tf=TimeFrame.tf_1h, 42 | market=Market.FUTURES, 43 | from_time=from_time, 44 | to_time=to_time, 45 | ) 46 | for kline in symbol_klines: 47 | print(str(kline)) 48 | 49 | bt_trades = client.get_symbol_recent_trades(symbol_spot, N=100) 50 | depth_futures = client.get_symbol_depth( 51 | symbol=symbol_spot, precision=6, size=50, market=Market.SPOT 52 | ) 53 | depth_spot = client.get_symbol_depth( 54 | symbol=symbol, precision=6, size=50, market=Market.FUTURES 55 | ) 56 | futures_open_interest = client.get_futures_open_interest(symbol) 57 | funding_rate = client.get_futures_funding_rate(symbol) 58 | [print(b) for b in client.get_account_balance(market=Market.FUTURES).items] 59 | [print(b) for b in client.get_account_balance(market=Market.SPOT).items] 60 | [print(b) for b in client.get_account_balance(market=Market.SPOT_MARGIN).items] 61 | fee_rate = client.get_spot_user_fee_rate() 62 | bt_trade_fee = client.get_spot_trade_fee_rate(symbol_spot) 63 | 64 | # ------------- WEB SOCKETS 65 | client.subscribe_private(Market.FUTURES, [BtFuturesTPrivatePositionChannel]) 66 | client.subscribe_private( 67 | Market.FUTURES, [BtFuturesTPrivateAssetChannel], ["ETH", "USDT"] 68 | ) 69 | client.subscribe_public(Market.FUTURES, [BtFuturesTickerChannel]) 70 | client.subscribe_public( 71 | Market.FUTURES, 72 | [ 73 | BtFuturesSocketKlineChannels.K_LINE_CHANNEL_1HOUR, 74 | BtFuturesSocketDepthChannels.DEPTH_CHANNEL_5LEVEL, 75 | ], 76 | [symbol], 77 | ) 78 | 79 | client.start_websockets( 80 | Market.FUTURES, on_message=lambda message: print(f"Message: {message}") 81 | ) 82 | client.subscribe_public( 83 | Market.SPOT, 84 | [ 85 | BtSpotSocketKlineChannels.K_LINE_CHANNEL_1HOUR, 86 | BtSpotSocketDepthChannels.DEPTH_CHANNEL_5LEVEL, 87 | BtSpotTradeChannel, 88 | BtSpotTickerChannel, 89 | ], 90 | symbols=[symbol_spot], 91 | ) 92 | client.subscribe_private(Market.SPOT, [BtSpotOrderChannel], symbols=[symbol_spot]) 93 | 94 | client.start_websockets( 95 | Market.SPOT, on_message=lambda message: print(f" {message}") 96 | ) 97 | client.wait_for_socket_connection(market=Market.FUTURES) 98 | client.wait_for_socket_connection(market=Market.SPOT, is_public=False) 99 | input("Press any key") 100 | client.unsubscribe_private(Market.FUTURES, [BtFuturesTPrivatePositionChannel]) 101 | client.unsubscribe_private(Market.FUTURES, [BtFuturesSocketDepthChannels], [symbol]) 102 | client.stop_websockets(Market.FUTURES) 103 | client.stop_websockets(Market.SPOT) 104 | # ------------- ORDER 105 | order = client.submit_order( 106 | market=Market.SPOT_MARGIN, 107 | symbol="BTC_USDT", 108 | side=SpotSide.BUY, 109 | size=0.005, 110 | price=1000, 111 | ) 112 | order = client.submit_order( 113 | market=Market.SPOT_MARGIN, 114 | order_type=OrderType.MARKET, 115 | symbol="BTC_USDT", 116 | side=SpotSide.BUY, 117 | size=6, 118 | price=1000, 119 | ) 120 | order = client.submit_order( 121 | market=Market.SPOT_MARGIN, 122 | order_type=OrderType.MARKET, 123 | symbol="BTC_USDT", 124 | side=SpotSide.SELL, 125 | size=6, 126 | price=1000, 127 | ) 128 | order = client.update_order_details(order) 129 | client.cancel_order(order) 130 | order = client.submit_order( 131 | market=Market.FUTURES, 132 | symbol="ETHUSDT", 133 | side=FuturesSide.BUY_OPEN_LONG, 134 | size=1, 135 | price=70, 136 | open_type=OrderOpenType.CROSS, 137 | ) 138 | client.update_order_details(order) 139 | 140 | client.cancel_order(order) 141 | order = client.update_order_details(order) 142 | 143 | print( 144 | client.submit_order( 145 | market=Market.FUTURES, 146 | symbol=symbol_eth, 147 | order_type=OrderType.MARKET, 148 | side=FuturesSide.SELL_OPEN_SHORT, 149 | size=1, 150 | open_type=OrderOpenType.CROSS, 151 | ) 152 | ) 153 | positions = client.get_futures_position_details(symbol_eth) 154 | amount = [p for p in positions if p.symbol == "ETHUSDT" and p.current_amount != 0][ 155 | 0 156 | ].current_amount 157 | 158 | print( 159 | client.close_futures_position( 160 | symbol=symbol_eth, 161 | position_side=Position.SHORT, 162 | open_type=OrderOpenType.CROSS, 163 | ) 164 | ) 165 | print( 166 | client.submit_order( 167 | market=Market.SPOT, 168 | symbol=symbol_spot, 169 | order_type=OrderType.MARKET, 170 | side=SpotSide.BUY, 171 | size=10, 172 | ) 173 | ) 174 | print( 175 | client.submit_order( 176 | market=Market.SPOT, 177 | symbol=symbol_spot, 178 | order_type=OrderType.MARKET, 179 | side=SpotSide.SELL, 180 | size=0.00050000, 181 | ) 182 | ) 183 | # ------------- MARGIN 184 | rate = client.spot_margin_borrowing_rate(symbol_spot) 185 | b_records = client.spot_margin_get_borrow_record(symbol_spot) 186 | r_records = client.spot_margin_get_repay_record(symbol_spot) 187 | client.spot_margin_borrow(symbol_spot, "BTC", 0.005) 188 | client.spot_margin_repay(symbol_spot, "BTC", 0.005) 189 | -------------------------------------------------------------------------------- /examples/trading_bot/backtesting.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "is_executing": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "%matplotlib inline\n", 12 | "\n", 13 | "from hftcryptoapi import BitmartClient\n", 14 | "from hftcryptoapi.bitmart.data import *\n", 15 | "from datetime import datetime, timedelta\n", 16 | "import pandas as pd\n", 17 | "from typing import List, Dict, Any\n", 18 | "\n", 19 | "client = BitmartClient()\n", 20 | "symbol = \"BTCUSDT\"\n", 21 | "to_time = datetime.now()\n", 22 | "from_time = to_time - timedelta(days=30)\n", 23 | "klines = client.get_symbol_kline(symbol=symbol, market=Market.FUTURES, tf=TimeFrame.tf_1h, from_time=from_time, to_time=to_time)\n", 24 | "\n", 25 | "\n", 26 | "def to_dataframe(kl: List[Kline]) -> pd.DataFrame:\n", 27 | " data = [dict(timestamp=k.date_time, open=k.open, high=k.high, low=k.low, close=k.close) for k in kl]\n", 28 | "\n", 29 | " df = pd.DataFrame(data=data, columns=[\"timestamp\", \"open\", \"high\", \"low\", \"close\"])\n", 30 | " df.set_index(\"timestamp\", inplace=True)\n", 31 | " return df\n", 32 | "\n", 33 | "df = to_dataframe(klines)\n", 34 | "df" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 1, 40 | "metadata": { 41 | "ExecuteTime": { 42 | "end_time": "2024-04-13T09:55:11.097508Z", 43 | "start_time": "2024-04-13T09:55:10.655383Z" 44 | } 45 | }, 46 | "outputs": [ 47 | { 48 | "ename": "NameError", 49 | "evalue": "name 'pd' is not defined", 50 | "output_type": "error", 51 | "traceback": [ 52 | "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", 53 | "\u001B[0;31mNameError\u001B[0m Traceback (most recent call last)", 54 | "Cell \u001B[0;32mIn[1], line 7\u001B[0m\n\u001B[1;32m 4\u001B[0m BB_WINDOW \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m20\u001B[39m\n\u001B[1;32m 5\u001B[0m RSI_WINDOW \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m14\u001B[39m\n\u001B[0;32m----> 7\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21madd_indicators\u001B[39m(df: \u001B[43mpd\u001B[49m\u001B[38;5;241m.\u001B[39mDataFrame, rsi_window: \u001B[38;5;28mint\u001B[39m \u001B[38;5;241m=\u001B[39m RSI_WINDOW, bb_window: \u001B[38;5;28mint\u001B[39m \u001B[38;5;241m=\u001B[39m BB_WINDOW):\n\u001B[1;32m 8\u001B[0m df[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mrsi\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m rsi(df\u001B[38;5;241m.\u001B[39mclose, window\u001B[38;5;241m=\u001B[39mrsi_window)\n\u001B[1;32m 9\u001B[0m bb \u001B[38;5;241m=\u001B[39m BollingerBands(df\u001B[38;5;241m.\u001B[39mclose, window\u001B[38;5;241m=\u001B[39mbb_window)\n", 55 | "\u001B[0;31mNameError\u001B[0m: name 'pd' is not defined" 56 | ] 57 | } 58 | ], 59 | "source": [ 60 | "from ta.momentum import rsi\n", 61 | "from ta.volatility import BollingerBands\n", 62 | "\n", 63 | "BB_WINDOW = 20\n", 64 | "RSI_WINDOW = 14\n", 65 | "\n", 66 | "def add_indicators(df: pd.DataFrame, rsi_window: int = RSI_WINDOW, bb_window: int = BB_WINDOW):\n", 67 | " df[\"rsi\"] = rsi(df.close, window=rsi_window)\n", 68 | " bb = BollingerBands(df.close, window=bb_window)\n", 69 | " df[\"bb_upper\"] = bb.bollinger_hband()\n", 70 | " df['bb_lower'] = bb.bollinger_lband()\n", 71 | " df.dropna(inplace=True)\n", 72 | "\n", 73 | " return df\n", 74 | "\n", 75 | "add_indicators(df)\n", 76 | "df\n", 77 | "df[[\"close\", \"bb_upper\", \"bb_lower\"]].plot()" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "import matplotlib.pyplot as plt\n", 87 | "\n", 88 | "fig, axs = plt.subplots(2, 1, sharex=\"row\", gridspec_kw={\"height_ratios\": [5, 1]})\n", 89 | "\n", 90 | "df[[\"close\", \"bb_upper\", \"bb_lower\"]].plot(ax=axs[0])\n", 91 | "df.rsi.plot(ax=axs[1], label=\"rsi\")\n", 92 | "axs[1].legend()\n", 93 | "axs[0].get_xaxis().set_visible(False)\n", 94 | "\n", 95 | "def should_buy(r: pd.Series) -> bool:\n", 96 | " return r.rsi < 30 and r.close < r.bb_lower\n", 97 | "\n", 98 | "\n", 99 | "def should_sell(r: pd.Series) -> bool:\n", 100 | " return r.rsi > 70 and r.close > r.bb_upper\n", 101 | "\n", 102 | "df['buy_signal'] = df.apply(should_buy, axis=1)\n", 103 | "df['sell_signal'] = df.apply(should_sell, axis=1)\n", 104 | "\n", 105 | "\n", 106 | "df_buy = df[df.buy_signal]\n", 107 | "df_sell = df[df.sell_signal]\n", 108 | "\n", 109 | "axs[0].scatter(df_buy.index, df_buy.close, marker=\"^\", color=\"green\")\n", 110 | "axs[0].scatter(df_sell.index, df_sell.close, marker=\"v\", color=\"red\")\n", 111 | "\n", 112 | "plt.show()\n", 113 | "\n", 114 | "\n" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": null, 120 | "metadata": {}, 121 | "outputs": [], 122 | "source": [ 123 | "trades: List[Dict[str, Any]] = []\n", 124 | "entry_side = None\n", 125 | "entry_price = None\n", 126 | "\n", 127 | "def open(side: Position, price: float):\n", 128 | " global entry_side, entry_price\n", 129 | " entry_side = side\n", 130 | " entry_price = price\n", 131 | "\n", 132 | "def close(price: float, close_time: datetime):\n", 133 | " global entry_side, entry_price\n", 134 | " trades.append(dict(open_price=entry_price, close_price=price, side=entry_side, close_time=close_time))\n", 135 | " entry_side = None\n", 136 | " entry_price = None\n", 137 | "\n", 138 | "\n", 139 | "for i, row in df[df.buy_signal | df.sell_signal].iterrows():\n", 140 | " if row.buy_signal and entry_side != Position.LONG:\n", 141 | " if entry_side is None:\n", 142 | " open(Position.LONG, row.close)\n", 143 | " else:\n", 144 | " close(row.close, i)\n", 145 | "\n", 146 | " if row.sell_signal and entry_side != Position.SHORT:\n", 147 | " if entry_side is None:\n", 148 | " open(Position.SHORT, row.close)\n", 149 | " else:\n", 150 | " close(row.close, i)\n", 151 | "\n", 152 | "trades_df = pd.DataFrame(trades)\n", 153 | "trades_df.set_index(\"close_time\", inplace=True)\n", 154 | "\n", 155 | "trades_df" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": null, 161 | "metadata": {}, 162 | "outputs": [], 163 | "source": [ 164 | "def get_profit(side: Position, open_price: float, close_price: float):\n", 165 | " if side == Position.SHORT:\n", 166 | " return (open_price - close_price) / open_price * 100\n", 167 | " else:\n", 168 | " return (close_price - open_price) / close_price * 100\n", 169 | "\n", 170 | "trades_df[\"profit\"] = trades_df.apply(lambda r: get_profit(r.side, r.open_price, r.close_price), axis=1)\n", 171 | "\n", 172 | "trades_df" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": null, 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "trades_df[\"profit\"].cumsum().plot()" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": null, 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "print(\"Backtesting summary:\")\n", 191 | "print(f\"Trades: %d\" % len(trades_df))\n", 192 | "print(\"Profit Sum: %.3f%%\" % trades_df.profit.sum())\n", 193 | "print(\"Max Trade profit.: %.3f%%\" % trades_df.profit.max())\n", 194 | "print(\"Min Trade profit.: %.3f%%\" % trades_df.profit.min())\n", 195 | "print(f\"Profit Per Trade(Avg.): %.3f%%\" % trades_df.profit.mean())" 196 | ] 197 | } 198 | ], 199 | "metadata": { 200 | "kernelspec": { 201 | "display_name": "venv", 202 | "language": "python", 203 | "name": "python3" 204 | }, 205 | "language_info": { 206 | "codemirror_mode": { 207 | "name": "ipython", 208 | "version": 3 209 | }, 210 | "file_extension": ".py", 211 | "mimetype": "text/x-python", 212 | "name": "python", 213 | "nbconvert_exporter": "python", 214 | "pygments_lexer": "ipython3", 215 | "version": "3.9.6" 216 | }, 217 | "orig_nbformat": 4, 218 | "vscode": { 219 | "interpreter": { 220 | "hash": "e684bff4c668e42c10b736d459ce9758b285075042060756d44f386a73347497" 221 | } 222 | } 223 | }, 224 | "nbformat": 4, 225 | "nbformat_minor": 2 226 | } 227 | -------------------------------------------------------------------------------- /examples/trading_bot/bot.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta 2 | 3 | import pandas as pd 4 | 5 | from bot_utils import ( 6 | to_dataframe, 7 | get_indicators, 8 | should_buy, 9 | should_sell, 10 | get_profit, 11 | BB_WINDOW, 12 | ) 13 | from config import * 14 | from hftcryptoapi import BitmartClient 15 | from hftcryptoapi.bitmart.data import * 16 | 17 | 18 | class TradingBot(object): 19 | def __init__(self, symbol: str, contract_size: int): 20 | self.client = BitmartClient(API_KEY, SECRET_KEY, MEMO) 21 | self.candles = pd.DataFrame() 22 | self.symbol = symbol 23 | self.contract_size = contract_size 24 | self.position_side: Optional[Position] = None 25 | self.profit: float = 0 26 | 27 | def preload(self): 28 | to_time = datetime.now() 29 | from_time = to_time - timedelta(hours=BB_WINDOW + 1) 30 | klines = self.client.get_symbol_kline( 31 | symbol=self.symbol, 32 | market=Market.FUTURES, 33 | tf=TimeFrame.tf_1h, 34 | from_time=from_time, 35 | to_time=to_time, 36 | ) 37 | 38 | self.candles = get_indicators(to_dataframe(klines)) 39 | 40 | def start(self): 41 | print("Starting bot...") 42 | self.preload() 43 | self.client.subscribe_public( 44 | market=Market.FUTURES, 45 | symbols=[self.symbol], 46 | channels=[BtFuturesSocketKlineChannels.K_LINE_CHANNEL_1HOUR], 47 | ) 48 | self.client.subscribe_private( 49 | market=Market.FUTURES, channels=[BtFuturesTPrivatePositionChannel] 50 | ) 51 | 52 | self.client.start_websockets(market=Market.FUTURES, on_message=self._on_message) 53 | 54 | def open(self, side: Position): 55 | print(f"Open position {side}") 56 | order_side = ( 57 | FuturesSide.BUY_OPEN_LONG 58 | if side == Position.LONG 59 | else FuturesSide.SELL_OPEN_SHORT 60 | ) 61 | self.client.submit_order( 62 | symbol=self.symbol, 63 | market=Market.FUTURES, 64 | order_type=OrderType.MARKET, 65 | size=self.contract_size, 66 | open_type=OrderOpenType.CROSS, 67 | side=order_side, 68 | ) 69 | 70 | self.position_side = side 71 | 72 | def close(self): 73 | print(f"Close position {self.position_side}") 74 | order_side = ( 75 | FuturesSide.SELL_CLOSE_LONG 76 | if self.position_side == Position.LONG 77 | else FuturesSide.BUY_CLOSE_SHORT 78 | ) 79 | self.client.submit_order( 80 | symbol=self.symbol, 81 | market=Market.FUTURES, 82 | order_type=OrderType.MARKET, 83 | size=self.contract_size, 84 | open_type=OrderOpenType.CROSS, 85 | side=order_side, 86 | ) 87 | 88 | self.position_side = None 89 | 90 | def trade_decision(self): 91 | row = self.candles.iloc[-1] 92 | print(f"rsi: {row.rsi} bb: {row.bb_upper} | {row.close} | {row.bb_lower}") 93 | 94 | if should_buy(row) and self.position_side != Position.LONG: 95 | if self.position_side is None: 96 | self.open(Position.LONG) 97 | else: 98 | self.close() 99 | elif should_sell(row) and self.position_side != Position.SHORT: 100 | if self.position_side is None: 101 | self.open(Position.SHORT) 102 | else: 103 | self.close() 104 | 105 | def _on_message(self, msg: Union[WebSocketKline, WebSocketPositionFutures]): 106 | if type(msg) is WebSocketKline: 107 | self.trade_decision() 108 | if self.candles.index[-1] < msg.date_time: 109 | self.preload() 110 | else: 111 | print(f"Position {msg.open_avg_price} [{msg.volume}]") 112 | if msg.volume == 0: 113 | profit = get_profit( 114 | msg.position_type, msg.open_avg_price, msg.close_avg_price 115 | ) 116 | print("POSITION CLOSED: %.3f" % profit) 117 | self.profit += profit 118 | 119 | def stop(self): 120 | print("Total profit is %.3f" % self.profit) 121 | self.client.stop_websockets(market=Market.FUTURES) 122 | pass 123 | 124 | 125 | bot = TradingBot(symbol="BTCUSDT", contract_size=5) 126 | bot.start() 127 | input("Press any key to exit...\r") 128 | bot.stop() 129 | -------------------------------------------------------------------------------- /examples/trading_bot/bot_utils.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import pandas as pd 4 | from ta.momentum import rsi 5 | from ta.volatility import BollingerBands 6 | 7 | from hftcryptoapi.bitmart.data import Kline 8 | from hftcryptoapi.bitmart.data.constants import Position 9 | 10 | 11 | def to_dataframe(kl: List[Kline]) -> pd.DataFrame: 12 | data = [ 13 | dict(timestamp=k.date_time, open=k.open, high=k.high, low=k.low, close=k.close) 14 | for k in kl 15 | ] 16 | df = pd.DataFrame(data=data, columns=["timestamp", "open", "high", "low", "close"]) 17 | df.set_index("timestamp", inplace=True) 18 | return df 19 | 20 | 21 | BB_WINDOW = 20 22 | RSI_WINDOW = 14 23 | 24 | 25 | def get_indicators( 26 | df: pd.DataFrame, rsi_window: int = RSI_WINDOW, bb_window: int = BB_WINDOW 27 | ): 28 | df["rsi"] = rsi(df.close, window=rsi_window) 29 | bb = BollingerBands(df.close, window=bb_window) 30 | df["bb_upper"] = bb.bollinger_hband() 31 | df["bb_lower"] = bb.bollinger_lband() 32 | df.dropna(inplace=True) 33 | 34 | return df 35 | 36 | 37 | def should_buy(r: pd.Series) -> bool: 38 | return r.rsi < 30 and r.close < r.bb_lower 39 | 40 | 41 | def should_sell(r: pd.Series) -> bool: 42 | return r.rsi > 70 and r.close > r.bb_upper 43 | 44 | 45 | def get_profit(side: Position, open_price: float, close_price: float): 46 | if side == Position.SHORT: 47 | return (open_price - close_price) / open_price * 100 48 | else: 49 | return (close_price - open_price) / close_price * 100 50 | -------------------------------------------------------------------------------- /examples/trading_bot/config.py: -------------------------------------------------------------------------------- 1 | API_KEY = "" 2 | SECRET_KEY = "" 3 | MEMO = "" 4 | -------------------------------------------------------------------------------- /examples/trading_bot/requirements.txt: -------------------------------------------------------------------------------- 1 | HFT-Crypto-API 2 | pandas 3 | ta 4 | matplotlib 5 | jupyter 6 | pandas -------------------------------------------------------------------------------- /examples/trading_bot/result.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/examples/trading_bot/result.pdf -------------------------------------------------------------------------------- /hftcryptoapi/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.0.1" 2 | 3 | from .bitmart.Bitmart import BitmartClient 4 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.0.1" 2 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/api_client.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import requests 4 | 5 | from . import exceptions, bitmart_utils 6 | from .bm_logging import log 7 | from .data import constants as c 8 | 9 | 10 | class PyClient(object): 11 | 12 | def __init__(self, api_key, secret_key, memo, url, timeout): 13 | """ 14 | :param api_key: Get from bitmart API page. 15 | :param secret_key: Get from bitmart API page. 16 | :param memo: Your memo 17 | :param url: Request Domain URL. 18 | :param timeout: (connection timeout, read timeout). 19 | """ 20 | self.API_KEY = api_key 21 | self.SECRET_KEY = secret_key 22 | self.MEMO = memo 23 | self.URL = url 24 | self.TIMEOUT = timeout 25 | 26 | @log 27 | def _request(self, method, request_path, params, auth): 28 | if method == c.GET or method == c.DELETE: 29 | url = self.URL + request_path + bitmart_utils.parse_params_to_str(params) 30 | else: 31 | url = self.URL + request_path 32 | 33 | # set body 34 | body = json.dumps(params) if method == c.POST else "" 35 | 36 | # set header 37 | if auth == c.Auth.NONE: 38 | header = bitmart_utils.get_header(api_key=None, sign=None, timestamp=None) 39 | elif auth == c.Auth.KEYED: 40 | header = bitmart_utils.get_header(self.API_KEY, sign=None, timestamp=None) 41 | else: 42 | timestamp = bitmart_utils.get_timestamp() 43 | sign = bitmart_utils.sign( 44 | bitmart_utils.pre_substring(timestamp, self.MEMO, str(body)), 45 | self.SECRET_KEY, 46 | ) 47 | header = bitmart_utils.get_header(self.API_KEY, sign, timestamp) 48 | 49 | # send request 50 | response = None 51 | if method == c.GET: 52 | response = requests.get(url, headers=header, timeout=self.TIMEOUT) 53 | elif method == c.POST: 54 | response = requests.post( 55 | url, data=body, headers=header, timeout=self.TIMEOUT 56 | ) 57 | elif method == c.DELETE: 58 | response = requests.delete(url, headers=header, timeout=self.TIMEOUT) 59 | 60 | # exception handle 61 | if not str(response.status_code) == "200": 62 | raise exceptions.APIException(response) 63 | try: 64 | res_header = response.headers 65 | r = dict() 66 | try: 67 | r["Remaining"] = res_header["X-BM-RateLimit-Remaining"] 68 | r["Limit"] = res_header["X-BM-RateLimit-Limit"] 69 | r["Reset"] = res_header["X-BM-RateLimit-Reset"] 70 | except Exception as e: 71 | print(f"Error while extracting from headers: {e}") 72 | return response 73 | 74 | except ValueError: 75 | raise exceptions.RequestException("Invalid Response: %s" % response.text) 76 | 77 | def _request_without_params(self, method, request_path, auth=c.Auth.NONE): 78 | return self._request(method, request_path, {}, auth) 79 | 80 | def _request_with_params(self, method, request_path, params, auth=c.Auth.NONE): 81 | return self._request(method, request_path, params, auth) 82 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/bitmart_errors.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, unique 2 | 3 | 4 | @unique 5 | class ContractErrors(Enum): 6 | ERROR_40001 = "Cloud account not found" 7 | ERROR_40002 = "out_trade_no not found" 8 | ERROR_40003 = "out_trade_no already existed" 9 | ERROR_40004 = "Cloud account count limit" 10 | ERROR_40005 = "Transfer vol precision error" 11 | ERROR_40006 = "Invalid ip error" 12 | ERROR_40007 = "Parse parameter error" 13 | ERROR_40008 = "Check nonce error" 14 | ERROR_40009 = "Check ver error" 15 | ERROR_40010 = "Not found func error" 16 | ERROR_40011 = "Invalid request" 17 | ERROR_40012 = "System error" 18 | ERROR_40013 = ( 19 | "Access too often: CLIENT_TIME_INVALID. Please check your system time." 20 | ) 21 | ERROR_40014 = "This contract is offline" 22 | ERROR_40015 = "This contract's exchange has been paused" 23 | ERROR_40016 = "This order would trigger user position liquidate" 24 | ERROR_40017 = ( 25 | "It is not possible to open and close simultaneously in the same position" 26 | ) 27 | ERROR_40018 = "Your position is closed" 28 | ERROR_40019 = "Your position is in liquidation delegating" 29 | ERROR_40020 = "Your position volume is not enough" 30 | ERROR_40021 = "The position is not exsit" 31 | ERROR_40022 = "The position is not isolated" 32 | ERROR_40023 = "The position would liquidate when sub margin" 33 | ERROR_40024 = "The position would be warnning of liquidation when sub margin" 34 | ERROR_40025 = "The position's margin should not be lower than the base limit" 35 | ERROR_40026 = "You cross margin position is in liquidation delegating" 36 | ERROR_40027 = "You contract account available balance not enough" 37 | ERROR_40028 = "Your plan order's count is more than system maximum limit." 38 | ERROR_40029 = "The order's leverage is too large." 39 | ERROR_40030 = "The order's leverage is too small." 40 | ERROR_40031 = "The deviation between current price and trigger price is too large." 41 | ERROR_40032 = "The plan order's life cycle is too long." 42 | ERROR_40033 = "The plan order's life cycle is too short." 43 | ERROR_40034 = "The Symbol is not exist" 44 | ERROR_40035 = "The order is not exist" 45 | ERROR_40036 = "The order status is invalid" 46 | ERROR_40037 = "The order id is not exist" 47 | ERROR_40038 = "The k-line step is invalid" 48 | ERROR_40039 = "The timestamp is invalid" 49 | ERROR_40040 = "The order leverage is invalid" 50 | ERROR_40041 = "The order side is invalid" 51 | ERROR_40042 = "The order type is invalid" 52 | ERROR_40043 = "The order precision is invalid" 53 | ERROR_40044 = "The order range is invalid" 54 | ERROR_40045 = "The order open type is invalid" 55 | ERROR_40046 = "The account is not opened futures" 56 | 57 | 58 | @unique 59 | class AuthenticationErrors(Enum): 60 | ERROR_30000 = "Not found" 61 | ERROR_30001 = "Header X-BM-KEY is empty" 62 | ERROR_30002 = "Header X-BM-KEY not found" 63 | ERROR_30003 = "Header X-BM-KEY has frozen" 64 | ERROR_30004 = "Header X-BM-SIGN is empty" 65 | ERROR_30005 = "Header X-BM-SIGN is wrong" 66 | ERROR_30006 = "Header X-BM-TIMESTAMP is empty" 67 | ERROR_30007 = "Header X-BM-TIMESTAMP range. Within a minute" 68 | ERROR_30008 = "Header X-BM-TIMESTAMP invalid format" 69 | ERROR_30010 = "IP is forbidden. We recommend enabling IP whitelist for API trading. After that reauth your account" 70 | ERROR_30011 = "Header X-BM-KEY over expire time" 71 | ERROR_30012 = "Header X-BM-KEY is forbidden to request it" 72 | ERROR_30013 = "Request too many requests" 73 | ERROR_30014 = "Service unavailable" 74 | 75 | 76 | @unique 77 | class AccountErrors(Enum): 78 | ERROR_60000 = "Invalid request (maybe the body is empty, or the int parameter passes string data)" 79 | ERROR_60001 = "Asset account type does not exist" 80 | ERROR_60002 = "currency does not exist" 81 | ERROR_60003 = "Currency has been closed recharge channel, if there is any problem, please consult customer service" 82 | ERROR_60004 = "Currency has been closed withdraw channel, if there is any problem, please consult customer service" 83 | ERROR_60005 = "Minimum amount error" 84 | ERROR_60006 = "Maximum withdraw precision is error" 85 | ERROR_60007 = "Only withdrawals from added addresses are allowed" 86 | ERROR_60008 = "Balance not enough" 87 | ERROR_60009 = "Beyond the limit" 88 | ERROR_60010 = "Withdraw id or deposit id not found" 89 | ERROR_60011 = "Address is not valid" 90 | ERROR_60012 = "This action is not supported in this currency(If IOTA, HLX recharge and withdraw calls are prohibited)" 91 | ERROR_61003 = "The specified sub-account could not be found" 92 | ERROR_61004 = "Duplicate requests (such as using an existing requestNo)" 93 | ERROR_60020 = "Your account is not allowed to recharge" 94 | ERROR_60021 = "Your account is not allowed to withdraw" 95 | ERROR_60022 = "No withdrawals for 24 hours" 96 | ERROR_60026 = "Sub-account does not have permission to operate" 97 | ERROR_60027 = "Only supports sub-account calls" 98 | ERROR_60028 = ( 99 | "Account is disabled for security reasons, please contact customer service" 100 | ) 101 | ERROR_60029 = "The account is frozen by the master account, please contact the master account to unfreeze the account" 102 | ERROR_61005 = "Asset transfer between accounts is not available" 103 | ERROR_61006 = "The sub-account api only supports organization accounts" 104 | ERROR_60030 = "Method Not Allowed" 105 | ERROR_60031 = "Unsupported Media Type" 106 | ERROR_60050 = "User account not found" 107 | ERROR_60051 = "Internal Server Error" 108 | 109 | 110 | @unique 111 | class SpotMarginErrors(Enum): 112 | ERROR_50000 = "Bad Request" 113 | ERROR_50001 = "Symbol not found" 114 | ERROR_50002 = "From Or To format error" 115 | ERROR_50003 = "Step format error" 116 | ERROR_50004 = "Kline size over 500" 117 | ERROR_50005 = "Order Id not found" 118 | ERROR_50006 = "Minimum size is %s" 119 | ERROR_50007 = "Maximum size is %s" 120 | ERROR_50008 = "Minimum price is %s" 121 | ERROR_50009 = "Minimum count*price is %s" 122 | ERROR_50010 = "RequestParam size is required" 123 | ERROR_50011 = "RequestParam price is required" 124 | ERROR_50012 = "RequestParam notional is required" 125 | ERROR_50013 = "Maximum limit*offset is %d" 126 | ERROR_50014 = "RequestParam limit is required" 127 | ERROR_50015 = "Minimum limit is 1" 128 | ERROR_50016 = "Maximum limit is %d" 129 | ERROR_50017 = "RequestParam offset is required" 130 | ERROR_50018 = "Minimum offset is 1" 131 | ERROR_50019 = "Invalid status. validate status is [1=Failed, 2=Success, 3=Frozen Failed, 4=Frozen Success, 5=Partially Filled, 6=Fully Fulled, 7=Canceling, 8=Canceled" 132 | ERROR_50020 = "Balance not enough" 133 | ERROR_50021 = "Invalid %s" 134 | ERROR_50022 = "Service unavailable" 135 | ERROR_50023 = "This Symbol can't place order by api" 136 | ERROR_50024 = "Order book size over 200" 137 | ERROR_50025 = "Maximum price is %s" 138 | ERROR_50026 = "The buy order price cannot be higher than the open price" 139 | ERROR_50027 = "The sell order price cannot be lower than the open price" 140 | ERROR_50028 = "Missing parameters" 141 | ERROR_50029 = "The parameters do not match" 142 | ERROR_50030 = "Order is already canceled" 143 | ERROR_50031 = "Order is already completed" 144 | ERROR_50032 = "Order does not exist" 145 | ERROR_50033 = ( 146 | "The order quantity should be greater than 0 and less than or equal to 10" 147 | ) 148 | ERROR_50034 = "The price is high and there is no matching depth" 149 | ERROR_50035 = "The price is low and there is no matching depth" 150 | ERROR_50036 = "Cancel failed, order is not revocable status" 151 | ERROR_50037 = "The maximum length of clientOrderId cannot exceed 32" 152 | ERROR_50038 = "ClientOrderId only allows a combination of numbers and letters" 153 | ERROR_50039 = "Order_id and clientOrderId cannot be empty at the same time" 154 | ERROR_50040 = "Symbol Not Available" 155 | ERROR_50041 = "Out of query time range" 156 | ERROR_51000 = "Currency not found" 157 | ERROR_51001 = "Margin Account not Opened" 158 | ERROR_51002 = "Margin Account Not Available" 159 | ERROR_51003 = "Account Limit" 160 | ERROR_51004 = "Exceed the maximum number of borrows available" 161 | ERROR_51005 = "Less than the minimum borrowable amount" 162 | ERROR_51006 = "Exceeds the amount to be repaid" 163 | ERROR_51007 = "order_mode not found" 164 | ERROR_51008 = "Operation is limited, please try again later" 165 | ERROR_51009 = "Parameter mismatch: limit order/market order quantity should be greater than the minimum number of should buy/sell" 166 | ERROR_51010 = "Parameter mismatch: limit order price should be greater than the minimum buy price" 167 | ERROR_51011 = "Parameter mismatch: Limit order quantity * price should be greater than the minimum transaction amount" 168 | ERROR_51012 = "Participation mismatch: the number of market order buy orders should be greater than the minimum buyable amount" 169 | ERROR_51013 = ( 170 | "Parameter mismatch: the price of market order buy order placed is too small" 171 | ) 172 | ERROR_51014 = ( 173 | "Parameter mismatch: the amount of market order sell orders placed is too small" 174 | ) 175 | ERROR_51015 = "Quantity is too small" 176 | ERROR_53000 = "Your account is frozen due to security policies. Please contact customer service" 177 | ERROR_53001 = "Your kyc country is restricted. Please contact customer service." 178 | ERROR_53002 = "Your account has not yet completed the kyc advanced certification, please complete first" 179 | ERROR_53003 = "No permission, please contact the main account" 180 | ERROR_53004 = "This trading pair is not available to trade in your region" 181 | ERROR_57001 = "Method Not Allowed" 182 | ERROR_58001 = "Unsupported Media Type" 183 | ERROR_59001 = "User account not found" 184 | ERROR_59002 = "Internal Server Error" 185 | ERROR_59003 = "Spot wallet call fail" 186 | ERROR_59004 = "Margin wallet service call exception" 187 | ERROR_59005 = "Margin wallet service restricted" 188 | ERROR_59006 = "Transfer fail" 189 | ERROR_59007 = "Get symbol risk data fail" 190 | ERROR_59008 = "Trading order failure" 191 | ERROR_59009 = "Loan success,but trading order failure" 192 | 193 | 194 | @unique 195 | class WebsocketErrors(Enum): 196 | ERROR_90001 = "Invalid message format" 197 | ERROR_90002 = "Invalid op param" 198 | ERROR_90003 = "Invalid args param" 199 | ERROR_90004 = "Invalid channel param" 200 | ERROR_91001 = "API KEY is empty" 201 | ERROR_91002 = "API KEY not found" 202 | ERROR_91003 = "API KEY has frozen" 203 | ERROR_91004 = "API KEY over expire time" 204 | ERROR_91005 = "Already logged in" 205 | ERROR_91006 = "User not logged in / User must be logged in" 206 | ERROR_91010 = "Param sign is empty" 207 | ERROR_91011 = "Param sign is wrong" 208 | ERROR_91021 = "Param timestamp is empty" 209 | ERROR_91022 = "Param timestamp range. Within a minute" 210 | ERROR_91023 = "Param timestamp invalid format" 211 | ERROR_92001 = "Invalid symbol param" 212 | ERROR_94001 = "Request frequency exceeds limit" 213 | ERROR_95000 = "Internal system error" 214 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/bitmart_utils.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import hmac 3 | 4 | from .data import constants as c 5 | 6 | 7 | def sign(message, secret_key): 8 | mac = hmac.new( 9 | bytes(secret_key, encoding="utf8"), 10 | bytes(message, encoding="utf-8"), 11 | digestmod="sha256", 12 | ) 13 | return mac.hexdigest() 14 | 15 | 16 | # timestamp + "#" + memo + "#" + queryString 17 | def pre_substring(timestamp, memo, body): 18 | return f"{str(timestamp)}#{memo}#{body}" 19 | 20 | 21 | def get_header(api_key, sign, timestamp): 22 | header = dict() 23 | header[c.CONTENT_TYPE] = c.APPLICATION_JSON 24 | header[c.USER_AGENT] = c.VERSION 25 | 26 | if api_key: 27 | header[c.X_BM_KEY] = api_key 28 | if sign: 29 | header[c.X_BM_SIGN] = sign 30 | if timestamp: 31 | header[c.X_BM_TIMESTAMP] = str(timestamp) 32 | 33 | return header 34 | 35 | 36 | def parse_params_to_str(params): 37 | url = "?" 38 | for key, value in params.items(): 39 | url = url + str(key) + "=" + str(value) + "&" 40 | 41 | return url[0:-1] 42 | 43 | 44 | def get_timestamp(): 45 | return str(int(datetime.datetime.now().timestamp() * 1000)) 46 | 47 | 48 | def round_time(dt=None, round_to=60): 49 | seconds = (dt.replace(tzinfo=None) - dt.min).seconds 50 | rounding = (seconds + round_to / 2) // round_to * round_to 51 | return dt + datetime.timedelta(0, rounding - seconds, -dt.microsecond) 52 | 53 | 54 | def get_kline_time(kline_type: c.BtFuturesSocketKlineChannels): 55 | items = kline_type.name.split("_") 56 | tf_name = ( 57 | items[-1] 58 | .lower() 59 | .replace("min", "m") 60 | .replace("day", "d") 61 | .replace("week", "w") 62 | .replace("hours", "h") 63 | .replace("hour", "h") 64 | ) 65 | now_ = datetime.datetime.now() 66 | now_ = now_.replace(second=0, microsecond=0) 67 | tf_val = int(tf_name[:-1]) 68 | if "m" in tf_name: 69 | cm, _ = divmod(now_.minute, tf_val) 70 | return now_.replace(minute=cm * tf_val) 71 | now_ = now_.replace(minute=0) 72 | if "h" in tf_name: 73 | ch, _ = divmod(now_.hour, tf_val) 74 | return now_.replace(hour=ch * tf_val) 75 | now_ = now_.replace(hour=0) 76 | # TODO: weeks not implemented 77 | return now_ 78 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/bm_logging.py: -------------------------------------------------------------------------------- 1 | class pyBitMartLog: 2 | logger_level = "test" 3 | 4 | """:return true or false""" 5 | 6 | @staticmethod 7 | def is_debug(): 8 | return pyBitMartLog.logger_level == "debug" 9 | 10 | """ 11 | :param 12 | logger_level: 'debug', 'info' 13 | """ 14 | 15 | @staticmethod 16 | def set_logger_level(logger_level: str): 17 | pyBitMartLog.logger_level = logger_level 18 | 19 | 20 | def log(func): 21 | def wrapper(*args, **kwargs): 22 | result = func(*args, **kwargs) 23 | if pyBitMartLog.is_debug(): 24 | print("response") 25 | print("\tbody:{}".format(result[0])) 26 | print("\tlimit:{}".format(result[1])) 27 | return result 28 | 29 | return wrapper 30 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/data/__init__.py: -------------------------------------------------------------------------------- 1 | from .constants import * 2 | from .rest import * 3 | from .ws import * 4 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/data/constants.py: -------------------------------------------------------------------------------- 1 | # Endpoint URL constants for API 2 | # Changelog: 3 | # 26/11/2022 First version 4 | 5 | from enum import Enum, EnumMeta, unique 6 | 7 | 8 | class MetaEnum(EnumMeta): 9 | def __contains__(cls, item): 10 | try: 11 | cls(item) 12 | except ValueError: 13 | return False 14 | return True 15 | 16 | 17 | """ Base urls for API endpoints """ 18 | # Domain constants 19 | API_URL = "https://api-cloud.bitmart.com" 20 | WS_URL = "wss://ws-manager-compress.bitmart.com/api?protocol=1.1" 21 | WS_URL_USER = "wss://ws-manager-compress.bitmart.com/user?protocol=1.1" 22 | CONTRACT_WS_URL = "wss://openapi-ws.bitmart.com/api?protocol=1.1" 23 | CONTRACT_WS_URL_USER = "wss://openapi-ws.bitmart.com/user?protocol=1.1" 24 | 25 | # http headers 26 | CONTENT_TYPE = "Content-Type" 27 | USER_AGENT = "User-Agent" 28 | X_BM_KEY = "X-BM-KEY" 29 | X_BM_SIGN = "X-BM-SIGN" 30 | X_BM_TIMESTAMP = "X-BM-TIMESTAMP" 31 | APPLICATION_JSON = "application/json" 32 | GET = "GET" 33 | POST = "POST" 34 | DELETE = "DELETE" 35 | VERSION = "0.1" 36 | 37 | # connection timeout, read timeout 38 | TIMEOUT = (5, 10) 39 | 40 | # 1 Spot Market API 41 | # System Status 42 | SYSTEM_TIME = "/system/time" 43 | SERVICE_STATUS = "/system/service" 44 | 45 | # Public Market Data 46 | SPOT_CURRENCY_LIST = "/spot/v1/currencies" 47 | SPOT_TRADING_PAIRS_LIST = "/spot/v1/symbols" 48 | SPOT_TRADING_PAIRS_DETAILS = "/spot/v1/symbols/details" 49 | SPOT_TICKER = "/spot/v2/ticker" 50 | SPOT_TICKER_DETAILS = "/spot/v1/ticker_detail" 51 | SPOT_K_LIE_STEP = "/spot/v1/steps" 52 | SPOT_K_LINE = "/spot/v1/symbols/kline" 53 | SPOT_BOOK_DEPTH = "/spot/v1/symbols/book" 54 | SPOT_RECENT_TRADES = "/spot/v1/symbols/trades" 55 | 56 | # Sub-Account Data 57 | MAIN_ACCOUNT_SPOT_ASSET = "/account/sub-account/main/v1/sub-to-main" 58 | SUB_ACCOUNT_SPOT_ASSET_TRANSFER = "/account/sub-account/sub/v1/sub-to-main" 59 | MAIN_ACCOUNT_SPOT_ASSET_TRANSFER = "/account/sub-account/main/v1/main-to-sub" 60 | SUB_ACCOUNT_SUB2SUB_SPOT_ASSET_TRANSFER = "/account/sub-account/sub/v1/sub-to-sub" 61 | MAIN_ACCOUNT_SUB2SUB_SPOT_ASSET_TRANSFER = "/account/sub-account/main/v1/sub-to-sub" 62 | MAIN_ACCOUNT_TRANSFER_LIST = "/account/sub-account/main/v1/transfer-list" 63 | ACCOUNT_TRANSFER_HISTORY = "/account/sub-account/v1/transfer-history" 64 | SUB_ACCOUNT_BALANCE = "/account/sub-account/main/v1/wallet" 65 | ALL_SUB_ACCOUNTS_LIST = "/account/sub-account/main/v1/subaccount-list" 66 | 67 | ## Funding Account Data 68 | ACCOUNT_BALANCE = "/account/v1/wallet" 69 | ACOUNT_ALL_CURRENCIES = "/account/v1/currencies" 70 | ACCOUNT_SPOT_BALANCE = "/spot/v1/wallet" 71 | ACCOUNT_DEPOSIT_ADDRESS = "/account/v1/deposit/address" 72 | ACCOUNT_WITHDRAW_QUOTA = "/account/v1/withdraw/charge" 73 | ACCOUNT_WITHDRAW = "/account/v1/withdraw/apply" 74 | ACCOUNT_WITHDRAW_DEPOSIT_HISTORY = "/account/v2/deposit-withdraw/history" 75 | ACCOUNT_DEPOSIT_WITHDRAW_DETAILS = "/account/v1/deposit-withdraw/detail" 76 | ACCOUNT_MARGIN_DETAILS = "/spot/v1/margin/isolated/account" 77 | ACCOUNT_MARGIN_ASSET_TRANSFER = "/spot/v1/margin/isolated/transfer" 78 | ACCOUNT_USER_FEE = "/spot/v1/user_fee" 79 | ACCOUNT_TRADE_FEE = "/spot/v1/trade_fee" 80 | 81 | ## Spot /Margin Trading 82 | SPOT_PLACE_ORDER = "/spot/v2/submit_order" 83 | SPOT_MARGIN_PLACE_ORDER = "/spot/v1/margin/submit_order" 84 | SPOT_BATCH_ORDER = "/spot/v2/batch_orders" 85 | SPOT_CANCEL_ORDER = "/spot/v3/cancel_order" 86 | SPOT_CANCEL_ALL_ORDERS = "/spot/v1/cancel_orders" 87 | SPOT_GET_ORDER_DETAILS = "/spot/v2/order_detail" 88 | SPOT_USER_ORDER_HISTORY = "/spot/v3/orders" 89 | SPOT_USER_TRADE_HISTORY = "/spot/v2/trades" 90 | 91 | ## Margin Loan 92 | MARGIN_BORROW = "/spot/v1/margin/isolated/borrow" 93 | MARING_REPAY = "/spot/v1/margin/isolated/repay" 94 | MARGIN_BORROW_RECORD = "/spot/v1/margin/isolated/borrow_record" 95 | MARING_REPAYMENT_RECORD = "/spot/v1/margin/isolated/repay_record" 96 | MARGIN_TRADING_PAIR_BORROW_RATE_AND_AMOUNT = "/spot/v1/margin/isolated/pairs" 97 | 98 | # 2 USD-M Futures Market API 99 | # Futures Market Data 100 | FUTURES_CONTRACT_DETAILS = "/contract/public/details" 101 | FUTURES_MARKET_DEPTH = "/contract/public/depth" 102 | FUTURES_OPEN_INTEREST = "/contract/public/open-interest" 103 | FUTURES_FUNDING_RATE = "/contract/public/funding-rate" 104 | FUTURES_K_LINE = "/contract/public/kline" 105 | 106 | ## Futures Account Data 107 | FUTURES_CONTRACT_ASSETS_DETAIL = "/contract/private/assets-detail" 108 | 109 | ## Futures Trading 110 | FUTURES_ORDER_DETAIL = "/contract/private/order" 111 | FUTURES_ORDER_HISTORY = "/contract/private/order-history" 112 | FUTURES_CURRENT_POSITION = "/contract/private/position" 113 | FUTURES_TRADE_DETAIL = "/contract/private/trades" 114 | FUTURES_SUBMIT_ORDER = "/contract/private/submit-order" 115 | FUTURES_CANCEL_ORDER = "/contract/private/cancel-order" 116 | FUTURES_CANCEL_ALL_ORDERS = "/contract/private/cancel-orders" 117 | 118 | 119 | @unique 120 | class Auth(int, Enum): 121 | NONE = 1 122 | KEYED = 2 123 | SIGNED = 3 124 | 125 | 126 | class Sort(str, Enum): 127 | ASC = "asc" 128 | DESC = "desc" 129 | 130 | 131 | @unique 132 | class Exchange(int, Enum): 133 | BITMART = 1 134 | BINANCE = 2 135 | HUOBI = 3 136 | 137 | 138 | @unique 139 | class ServiceStatus(int, Enum): 140 | WAITING = 0 141 | WORKING = 1 142 | COMPLETED = 2 143 | 144 | 145 | @unique 146 | class TimeFrame(int, Enum): 147 | tf_1m = 1 148 | tf_5m = 5 149 | tf_15m = 15 150 | tf_30m = 30 151 | tf_1h = 60 152 | tf_2h = 120 153 | tf_4h = 240 154 | tf_1d = 60 * 24 155 | tf_1w = 60 * 24 * 7 156 | 157 | 158 | @unique 159 | class Market(str, Enum): 160 | SPOT = "spot" 161 | FUTURES = "futures" 162 | SPOT_MARGIN = "margin" 163 | 164 | 165 | @unique 166 | class OrderMode(str, Enum): 167 | SPOT = "spot" 168 | ISOLATED_MARGIN = "iso_margin" 169 | 170 | 171 | @unique 172 | class OrderType(str, Enum): 173 | LIMIT = "limit" 174 | MARKET = "market" 175 | LIMIT_MAKER = "limit_maker" # only for spot market 176 | IOC = "ioc" # only for spot market 177 | 178 | 179 | @unique 180 | class SpotSide(str, Enum): 181 | BUY = "buy" 182 | SELL = "sell" 183 | 184 | 185 | @unique 186 | class Position(int, Enum): 187 | LONG = 1 188 | SHORT = 2 189 | 190 | 191 | @unique 192 | class FuturesSide(int, Enum, metaclass=MetaEnum): 193 | BUY_OPEN_LONG = 1 194 | BUY_CLOSE_SHORT = 2 195 | SELL_CLOSE_LONG = 3 196 | SELL_OPEN_SHORT = 4 197 | 198 | 199 | @unique 200 | class OrderOpenType(str, Enum): 201 | ISOLATED = "isolated" 202 | CROSS = "cross" 203 | 204 | 205 | @unique 206 | class OrderState(int, Enum): 207 | STATUS_CHECK = 2 208 | ORDER_SUCCESS = 4 209 | PARTIALLY_FILLED = 5 210 | FULLY_FILLED = 6 211 | CANCELLED = 8 212 | OUTSTANDING = 9 213 | MIX_6_8_11 = 10 214 | PARTIALLY_FILLED_AND_CANCELED = 11 215 | 216 | 217 | @unique 218 | class ExecType(str, Enum): 219 | MAKER = "M" 220 | TAKER = "T" 221 | 222 | 223 | @unique 224 | class TradeOrderType(int, Enum): 225 | REGULAR = 0 226 | MAKER_ONLY = 1 227 | FILL_OR_KILL = 2 228 | IMMEDIATE_OR_CANCEL = 3 229 | 230 | 231 | @unique 232 | class WayType(int, Enum): 233 | ASK = 1 234 | BID = 2 235 | 236 | 237 | @unique 238 | class FuturesContractType(int, Enum): 239 | PERPETUAL = 1 240 | FUTURES = 2 241 | 242 | 243 | @unique 244 | class BtWebSocket(str, Enum): 245 | """Base urls for websocket endpoints""" 246 | 247 | PUBLIC = "wss://ws-manager-compress.bitmart.com/api?protocol=1.1" 248 | PRIVATE = "wss://ws-manager-compress.bitmart.com/user?protocol=1.1" 249 | 250 | 251 | @unique 252 | class BtSocketOperation(str, Enum, metaclass=MetaEnum): 253 | """Base operation data for Bitmart websockets""" 254 | 255 | SUBSCRIBE = "subscribe" 256 | UNSUBSCRIBE = "unsubscribe" 257 | LOGIN = "login" 258 | 259 | 260 | @unique 261 | class BtSpotSocketKlineChannels(str, Enum): 262 | """Base websocket channels for Bitmart Spot Klines""" 263 | 264 | K_LINE_CHANNEL_1MIN = "spot/kline1m" 265 | K_LINE_CHANNEL_3MIN = "spot/kline3m" 266 | K_LINE_CHANNEL_5MIN = "spot/kline5m" 267 | K_LINE_CHANNEL_15MIN = "spot/kline15m" 268 | K_LINE_CHANNEL_30MIN = "spot/kline30m" 269 | K_LINE_CHANNEL_1HOUR = "spot/kline1H" 270 | K_LINE_CHANNEL_2HOURS = "spot/kline2H" 271 | K_LINE_CHANNEL_4HOURS = "spot/kline4H" 272 | K_LINE_CHANNEL_1DAY = "spot/kline1D" 273 | K_LINE_CHANNEL_1WEEK = "spot/kline1W" 274 | K_LINE_CHANNEL_1MONTH = "spot/kline1M" 275 | 276 | 277 | @unique 278 | class BtFuturesSocketKlineChannels(str, Enum): 279 | K_LINE_CHANNEL_1MIN = "futures/klineBin1m" 280 | K_LINE_CHANNEL_5MIN = "futures/klineBin5m" 281 | K_LINE_CHANNEL_15MIN = "futures/klineBin15m" 282 | K_LINE_CHANNEL_30MIN = "futures/klineBin30m" 283 | K_LINE_CHANNEL_1HOUR = "futures/klineBin1h" 284 | K_LINE_CHANNEL_2HOURS = "futures/klineBin2h" 285 | K_LINE_CHANNEL_4HOURS = "futures/klineBin4h" 286 | K_LINE_CHANNEL_1DAY = "futures/klineBin1d" 287 | K_LINE_CHANNEL_1WEEK = "futures/klineBin1w" 288 | 289 | 290 | @unique 291 | class BtSpotSocketDepthChannels(str, Enum): 292 | DEPTH_CHANNEL_5LEVEL = "spot/depth5" 293 | DEPTH_CHANNEL_20LEVEL = "spot/dept20" 294 | DEPTH_CHANNEL_50LEVEL = "spot/depth50" 295 | 296 | 297 | @unique 298 | class BtFuturesSocketDepthChannels(str, Enum): 299 | DEPTH_CHANNEL_5LEVEL = "futures/depth5" 300 | DEPTH_CHANNEL_20LEVEL = "futures/dept20" 301 | DEPTH_CHANNEL_50LEVEL = "futures/depth50" 302 | 303 | 304 | BtSpotTickerChannel = "spot/ticker" 305 | BtSpotTradeChannel = "spot/trade" 306 | BtSpotOrderChannel = "spot/user/order" 307 | BtFuturesTickerChannel = "futures/ticker" 308 | BtFuturesTPrivatePositionChannel = "futures/position" 309 | BtFuturesTPrivateAssetChannel = "futures/asset" 310 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/data/ws.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from hftcryptoapi.bitmart.data.constants import * 4 | 5 | 6 | class WebSocketTickerSpot(object): 7 | def __init__( 8 | self, symbol, last_price, base_volume_24h, high_24h, low_24h, open_24h, s_t 9 | ): 10 | self.base_volume_24h = float(base_volume_24h) 11 | self.high_24h = float(high_24h) 12 | self.last_price = float(last_price) 13 | self.low_24h = float(low_24h) 14 | self.open_24h = float(open_24h) 15 | self.date_time = datetime.fromtimestamp(s_t) 16 | self.symbol = symbol 17 | 18 | 19 | class WebSocketTickerFutures(object): 20 | def __init__(self, symbol, volume_24, fair_price, last_price, range): 21 | self.symbol = symbol 22 | self.volume_24 = float(volume_24) 23 | self.fair_price = float(fair_price) 24 | self.last_price = float(last_price) 25 | self.range = float(range) 26 | 27 | 28 | class WebSocketKline(object): 29 | def __init__(self, symbol: str, candle: list, market: Market): 30 | self.market = market 31 | self.symbol = symbol 32 | if market == Market.SPOT: 33 | idx = 1 34 | self.date_time = datetime.fromtimestamp(candle[0] / 1000) 35 | else: 36 | idx = 0 37 | self.date_time = datetime.now() 38 | self.open = float(candle[idx]) 39 | self.high = float(candle[idx + 1]) 40 | self.low = float(candle[idx + 2]) 41 | self.close = float(candle[idx + 3]) 42 | self.volume = float(candle[idx + 4]) 43 | 44 | def __str__(self): 45 | return f"{self.date_time}: {self.open}, {self.high}, {self.low}, {self.close} | {self.volume}" 46 | 47 | 48 | class WebSocketDepthSpot: 49 | def __init__(self, symbol: str, asks: list, bids: list, ms_t: float): 50 | self.date_time = datetime.fromtimestamp(ms_t / 1000) 51 | self.symbol = symbol 52 | self.asks_price = asks[0] 53 | self.asks_quantity = asks[1] 54 | self.bids_price = bids[0] 55 | self.bids_quantity = bids[1] 56 | self.best_bid = "" # TODO: implement 57 | self.best_ask = "" # TODO: implement 58 | 59 | 60 | class WebSocketDepthFutures: 61 | def __init__(self, symbol: str, way: int, ms_t: float, depths: list): 62 | self.symbol = symbol 63 | self.way = WayType(way) 64 | self.date_time = datetime.fromtimestamp(ms_t / 1000) 65 | self.depths = depths 66 | 67 | 68 | class WebSocketDepthElementFutures: 69 | def __init__(self, price, volume): 70 | self.price = float(price) 71 | self.volume = float(volume) 72 | 73 | 74 | class WebSocketTrade: 75 | def __init__(self, symbol, side, price, size, s_t): 76 | self.symbol = symbol 77 | self.side = side 78 | self.price = float(price) 79 | self.size = float(size) 80 | self.date_time = datetime.fromtimestamp(s_t / 1000) 81 | 82 | 83 | class WebSocketLogin: 84 | def __init__(self, event): 85 | self.event = float(event) 86 | 87 | 88 | class WebSocketOrderProgress: 89 | def __init__( 90 | self, 91 | symbol, 92 | order_id, 93 | price, 94 | size, 95 | notional, 96 | side, 97 | order_type, 98 | ms_t, 99 | filled_size, 100 | filled_notional, 101 | margin_trading, 102 | trade_order_type, 103 | state, 104 | last_fill_price, 105 | last_fill_count, 106 | last_fill_time, 107 | exec_type, 108 | detail_id, 109 | client_order_id, 110 | ): 111 | self.symbol = symbol 112 | self.order_id = order_id 113 | self.price = float(price) 114 | self.size = float(size) 115 | self.notional = notional 116 | self.side = SpotSide(side) 117 | self.order_type = OrderType(order_type) 118 | self.date_time = datetime.fromtimestamp(ms_t / 1000) 119 | self.filled_size = float(filled_size) 120 | self.filled_notional = float(filled_notional) 121 | self.margin_trading = margin_trading 122 | self.trade_order_type = TradeOrderType(trade_order_type) 123 | self.state = OrderState(state) 124 | self.last_fill_price = float(last_fill_price) 125 | self.last_fill_count = float(last_fill_count) 126 | self.last_fill_time = datetime.fromtimestamp(last_fill_time / 1000) 127 | self.exec_type = ExecType(exec_type) 128 | self.detail_id = detail_id 129 | self.client_order_id = client_order_id 130 | 131 | 132 | class WebSocketAssetFutures(object): 133 | def __init__(self, currency, available_balance, position_deposit, frozen_balance): 134 | self.ticker = currency 135 | self.available_balance = float(available_balance) 136 | self.position_deposit = float(position_deposit) 137 | self.frozen_balance = float(frozen_balance) 138 | 139 | 140 | class WebSocketPositionFutures(object): 141 | def __init__( 142 | self, 143 | symbol, 144 | hold_volume, 145 | position_type, 146 | open_type, 147 | frozen_volume, 148 | close_volume, 149 | hold_avg_price, 150 | close_avg_price, 151 | open_avg_price, 152 | liquidate_price, 153 | create_time, 154 | update_time, 155 | ): 156 | self.ticker = symbol 157 | self.hold_volume = int(hold_volume) 158 | self.position_type = Position(position_type) 159 | self.open_type = ( 160 | OrderOpenType.ISOLATED if open_type == 1 else OrderOpenType.CROSS 161 | ) 162 | self.frozen_volume = int(frozen_volume) 163 | self.close_volume = int(close_volume) 164 | self.hold_avg_price = float(hold_avg_price) 165 | self.close_avg_price = float(close_avg_price) 166 | self.open_avg_price = float(open_avg_price) 167 | self.liquidate_price = float(liquidate_price) 168 | self.create_time = datetime.fromtimestamp(create_time / 1000) 169 | self.update_time = datetime.fromtimestamp(update_time / 1000) 170 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/doctrees/bitmart.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/hftcryptoapi/bitmart/docs/build/doctrees/bitmart.doctree -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/hftcryptoapi/bitmart/docs/build/doctrees/environment.pickle -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/hftcryptoapi/bitmart/docs/build/doctrees/index.doctree -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/doctrees/modules.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/hftcryptoapi/bitmart/docs/build/doctrees/modules.doctree -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: 9d8bd965e0cf0f637570c358038d51bf 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_sources/bitmart.rst.txt: -------------------------------------------------------------------------------- 1 | bitmart package 2 | =============== 3 | 4 | Submodules 5 | ---------- 6 | 7 | bitmart.Bitmart module 8 | ---------------------- 9 | 10 | .. automodule:: bitmart.Bitmart 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | bitmart.api\_client module 16 | -------------------------- 17 | 18 | .. automodule:: bitmart.api_client 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | bitmart.bitmart\_errors module 24 | ------------------------------ 25 | 26 | .. automodule:: bitmart.bitmart_errors 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | bitmart.bitmart\_exceptions module 32 | ---------------------------------- 33 | 34 | .. automodule:: bitmart.bitmart_exceptions 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | bitmart.bitmart\_objects module 40 | ------------------------------- 41 | 42 | .. automodule:: bitmart.bitmart_objects 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | bitmart.bitmart\_utils module 48 | ----------------------------- 49 | 50 | .. automodule:: bitmart.bitmart_utils 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | bitmart.bitmart\_websockets module 56 | ---------------------------------- 57 | 58 | .. automodule:: bitmart.bitmart_websockets 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | bitmart.bm\_logging module 64 | -------------------------- 65 | 66 | .. automodule:: bitmart.bm_logging 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | bitmart.client\_keys module 72 | --------------------------- 73 | 74 | .. automodule:: bitmart.client_keys 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | 79 | bitmart.constants module 80 | ------------------------ 81 | 82 | .. automodule:: bitmart.constants 83 | :members: 84 | :undoc-members: 85 | :show-inheritance: 86 | 87 | Module contents 88 | --------------- 89 | 90 | .. automodule:: bitmart 91 | :members: 92 | :undoc-members: 93 | :show-inheritance: 94 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. hftcryptoapi documentation master file, created by 2 | sphinx-quickstart on Mon Dec 5 23:14:33 2022. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to hftcryptoapi's documentation! 7 | ======================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_sources/modules.rst.txt: -------------------------------------------------------------------------------- 1 | bitmart 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | bitmart 8 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/_sphinx_javascript_frameworks_compat.js: -------------------------------------------------------------------------------- 1 | /* 2 | * _sphinx_javascript_frameworks_compat.js 3 | * ~~~~~~~~~~ 4 | * 5 | * Compatability shim for jQuery and underscores.js. 6 | * 7 | * WILL BE REMOVED IN Sphinx 6.0 8 | * xref RemovedInSphinx60Warning 9 | * 10 | */ 11 | 12 | /** 13 | * select a different prefix for underscore 14 | */ 15 | $u = _.noConflict(); 16 | 17 | 18 | /** 19 | * small helper function to urldecode strings 20 | * 21 | * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL 22 | */ 23 | jQuery.urldecode = function (x) { 24 | if (!x) { 25 | return x 26 | } 27 | return decodeURIComponent(x.replace(/\+/g, ' ')); 28 | }; 29 | 30 | /** 31 | * small helper function to urlencode strings 32 | */ 33 | jQuery.urlencode = encodeURIComponent; 34 | 35 | /** 36 | * This function returns the parsed url parameters of the 37 | * current request. Multiple values per key are supported, 38 | * it will always return arrays of strings for the value parts. 39 | */ 40 | jQuery.getQueryParameters = function (s) { 41 | if (typeof s === 'undefined') 42 | s = document.location.search; 43 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 44 | var result = {}; 45 | for (var i = 0; i < parts.length; i++) { 46 | var tmp = parts[i].split('=', 2); 47 | var key = jQuery.urldecode(tmp[0]); 48 | var value = jQuery.urldecode(tmp[1]); 49 | if (key in result) 50 | result[key].push(value); 51 | else 52 | result[key] = [value]; 53 | } 54 | return result; 55 | }; 56 | 57 | /** 58 | * highlight a given string on a jquery object by wrapping it in 59 | * span elements with the given class name. 60 | */ 61 | jQuery.fn.highlightText = function (text, className) { 62 | function highlight(node, addItems) { 63 | if (node.nodeType === 3) { 64 | var val = node.nodeValue; 65 | var pos = val.toLowerCase().indexOf(text); 66 | if (pos >= 0 && 67 | !jQuery(node.parentNode).hasClass(className) && 68 | !jQuery(node.parentNode).hasClass("nohighlight")) { 69 | var span; 70 | var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); 71 | if (isInSVG) { 72 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); 73 | } else { 74 | span = document.createElement("span"); 75 | span.className = className; 76 | } 77 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 78 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 79 | document.createTextNode(val.substr(pos + text.length)), 80 | node.nextSibling)); 81 | node.nodeValue = val.substr(0, pos); 82 | if (isInSVG) { 83 | var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); 84 | var bbox = node.parentElement.getBBox(); 85 | rect.x.baseVal.value = bbox.x; 86 | rect.y.baseVal.value = bbox.y; 87 | rect.width.baseVal.value = bbox.width; 88 | rect.height.baseVal.value = bbox.height; 89 | rect.setAttribute('class', className); 90 | addItems.push({ 91 | "parent": node.parentNode, 92 | "target": rect 93 | }); 94 | } 95 | } 96 | } else if (!jQuery(node).is("button, select, textarea")) { 97 | jQuery.each(node.childNodes, function () { 98 | highlight(this, addItems); 99 | }); 100 | } 101 | } 102 | 103 | var addItems = []; 104 | var result = this.each(function () { 105 | highlight(this, addItems); 106 | }); 107 | for (var i = 0; i < addItems.length; ++i) { 108 | jQuery(addItems[i].parent).before(addItems[i].target); 109 | } 110 | return result; 111 | }; 112 | 113 | /* 114 | * backward compatibility for jQuery.browser 115 | * This will be supported until firefox bug is fixed. 116 | */ 117 | if (!jQuery.browser) { 118 | jQuery.uaMatch = function (ua) { 119 | ua = ua.toLowerCase(); 120 | 121 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 122 | /(webkit)[ \/]([\w.]+)/.exec(ua) || 123 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 124 | /(msie) ([\w.]+)/.exec(ua) || 125 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || 126 | []; 127 | 128 | return { 129 | browser: match[1] || "", 130 | version: match[2] || "0" 131 | }; 132 | }; 133 | jQuery.browser = {}; 134 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; 135 | } 136 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/alabaster.css: -------------------------------------------------------------------------------- 1 | @import url("basic.css"); 2 | 3 | /* -- page layout ----------------------------------------------------------- */ 4 | 5 | body { 6 | font-family: Georgia, serif; 7 | font-size: 17px; 8 | background-color: #fff; 9 | color: #000; 10 | margin: 0; 11 | padding: 0; 12 | } 13 | 14 | 15 | div.document { 16 | width: 940px; 17 | margin: 30px auto 0 auto; 18 | } 19 | 20 | div.documentwrapper { 21 | float: left; 22 | width: 100%; 23 | } 24 | 25 | div.bodywrapper { 26 | margin: 0 0 0 220px; 27 | } 28 | 29 | div.sphinxsidebar { 30 | width: 220px; 31 | font-size: 14px; 32 | line-height: 1.5; 33 | } 34 | 35 | hr { 36 | border: 1px solid #B1B4B6; 37 | } 38 | 39 | div.body { 40 | background-color: #fff; 41 | color: #3E4349; 42 | padding: 0 30px 0 30px; 43 | } 44 | 45 | div.body > .section { 46 | text-align: left; 47 | } 48 | 49 | div.footer { 50 | width: 940px; 51 | margin: 20px auto 30px auto; 52 | font-size: 14px; 53 | color: #888; 54 | text-align: right; 55 | } 56 | 57 | div.footer a { 58 | color: #888; 59 | } 60 | 61 | p.caption { 62 | font-family: inherit; 63 | font-size: inherit; 64 | } 65 | 66 | 67 | div.relations { 68 | display: none; 69 | } 70 | 71 | 72 | div.sphinxsidebar a { 73 | color: #444; 74 | text-decoration: none; 75 | border-bottom: 1px dotted #999; 76 | } 77 | 78 | div.sphinxsidebar a:hover { 79 | border-bottom: 1px solid #999; 80 | } 81 | 82 | div.sphinxsidebarwrapper { 83 | padding: 18px 10px; 84 | } 85 | 86 | div.sphinxsidebarwrapper p.logo { 87 | padding: 0; 88 | margin: -10px 0 0 0px; 89 | text-align: center; 90 | } 91 | 92 | div.sphinxsidebarwrapper h1.logo { 93 | margin-top: -10px; 94 | text-align: center; 95 | margin-bottom: 5px; 96 | text-align: left; 97 | } 98 | 99 | div.sphinxsidebarwrapper h1.logo-name { 100 | margin-top: 0px; 101 | } 102 | 103 | div.sphinxsidebarwrapper p.blurb { 104 | margin-top: 0; 105 | font-style: normal; 106 | } 107 | 108 | div.sphinxsidebar h3, 109 | div.sphinxsidebar h4 { 110 | font-family: Georgia, serif; 111 | color: #444; 112 | font-size: 24px; 113 | font-weight: normal; 114 | margin: 0 0 5px 0; 115 | padding: 0; 116 | } 117 | 118 | div.sphinxsidebar h4 { 119 | font-size: 20px; 120 | } 121 | 122 | div.sphinxsidebar h3 a { 123 | color: #444; 124 | } 125 | 126 | div.sphinxsidebar p.logo a, 127 | div.sphinxsidebar h3 a, 128 | div.sphinxsidebar p.logo a:hover, 129 | div.sphinxsidebar h3 a:hover { 130 | border: none; 131 | } 132 | 133 | div.sphinxsidebar p { 134 | color: #555; 135 | margin: 10px 0; 136 | } 137 | 138 | div.sphinxsidebar ul { 139 | margin: 10px 0; 140 | padding: 0; 141 | color: #000; 142 | } 143 | 144 | div.sphinxsidebar ul li.toctree-l1 > a { 145 | font-size: 120%; 146 | } 147 | 148 | div.sphinxsidebar ul li.toctree-l2 > a { 149 | font-size: 110%; 150 | } 151 | 152 | div.sphinxsidebar input { 153 | border: 1px solid #CCC; 154 | font-family: Georgia, serif; 155 | font-size: 1em; 156 | } 157 | 158 | div.sphinxsidebar hr { 159 | border: none; 160 | height: 1px; 161 | color: #AAA; 162 | background: #AAA; 163 | 164 | text-align: left; 165 | margin-left: 0; 166 | width: 50%; 167 | } 168 | 169 | div.sphinxsidebar .badge { 170 | border-bottom: none; 171 | } 172 | 173 | div.sphinxsidebar .badge:hover { 174 | border-bottom: none; 175 | } 176 | 177 | /* To address an issue with donation coming after search */ 178 | div.sphinxsidebar h3.donation { 179 | margin-top: 10px; 180 | } 181 | 182 | /* -- body styles ----------------------------------------------------------- */ 183 | 184 | a { 185 | color: #004B6B; 186 | text-decoration: underline; 187 | } 188 | 189 | a:hover { 190 | color: #6D4100; 191 | text-decoration: underline; 192 | } 193 | 194 | div.body h1, 195 | div.body h2, 196 | div.body h3, 197 | div.body h4, 198 | div.body h5, 199 | div.body h6 { 200 | font-family: Georgia, serif; 201 | font-weight: normal; 202 | margin: 30px 0px 10px 0px; 203 | padding: 0; 204 | } 205 | 206 | div.body h1 { 207 | margin-top: 0; 208 | padding-top: 0; 209 | font-size: 240%; 210 | } 211 | 212 | div.body h2 { 213 | font-size: 180%; 214 | } 215 | 216 | div.body h3 { 217 | font-size: 150%; 218 | } 219 | 220 | div.body h4 { 221 | font-size: 130%; 222 | } 223 | 224 | div.body h5 { 225 | font-size: 100%; 226 | } 227 | 228 | div.body h6 { 229 | font-size: 100%; 230 | } 231 | 232 | a.headerlink { 233 | color: #DDD; 234 | padding: 0 4px; 235 | text-decoration: none; 236 | } 237 | 238 | a.headerlink:hover { 239 | color: #444; 240 | background: #EAEAEA; 241 | } 242 | 243 | div.body p, div.body dd, div.body li { 244 | line-height: 1.4em; 245 | } 246 | 247 | div.admonition { 248 | margin: 20px 0px; 249 | padding: 10px 30px; 250 | background-color: #EEE; 251 | border: 1px solid #CCC; 252 | } 253 | 254 | div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { 255 | background-color: #FBFBFB; 256 | border-bottom: 1px solid #fafafa; 257 | } 258 | 259 | div.admonition p.admonition-title { 260 | font-family: Georgia, serif; 261 | font-weight: normal; 262 | font-size: 24px; 263 | margin: 0 0 10px 0; 264 | padding: 0; 265 | line-height: 1; 266 | } 267 | 268 | div.admonition p.last { 269 | margin-bottom: 0; 270 | } 271 | 272 | div.highlight { 273 | background-color: #fff; 274 | } 275 | 276 | dt:target, .highlight { 277 | background: #FAF3E8; 278 | } 279 | 280 | div.warning { 281 | background-color: #FCC; 282 | border: 1px solid #FAA; 283 | } 284 | 285 | div.danger { 286 | background-color: #FCC; 287 | border: 1px solid #FAA; 288 | -moz-box-shadow: 2px 2px 4px #D52C2C; 289 | -webkit-box-shadow: 2px 2px 4px #D52C2C; 290 | box-shadow: 2px 2px 4px #D52C2C; 291 | } 292 | 293 | div.error { 294 | background-color: #FCC; 295 | border: 1px solid #FAA; 296 | -moz-box-shadow: 2px 2px 4px #D52C2C; 297 | -webkit-box-shadow: 2px 2px 4px #D52C2C; 298 | box-shadow: 2px 2px 4px #D52C2C; 299 | } 300 | 301 | div.caution { 302 | background-color: #FCC; 303 | border: 1px solid #FAA; 304 | } 305 | 306 | div.attention { 307 | background-color: #FCC; 308 | border: 1px solid #FAA; 309 | } 310 | 311 | div.important { 312 | background-color: #EEE; 313 | border: 1px solid #CCC; 314 | } 315 | 316 | div.note { 317 | background-color: #EEE; 318 | border: 1px solid #CCC; 319 | } 320 | 321 | div.tip { 322 | background-color: #EEE; 323 | border: 1px solid #CCC; 324 | } 325 | 326 | div.hint { 327 | background-color: #EEE; 328 | border: 1px solid #CCC; 329 | } 330 | 331 | div.seealso { 332 | background-color: #EEE; 333 | border: 1px solid #CCC; 334 | } 335 | 336 | div.topic { 337 | background-color: #EEE; 338 | } 339 | 340 | p.admonition-title { 341 | display: inline; 342 | } 343 | 344 | p.admonition-title:after { 345 | content: ":"; 346 | } 347 | 348 | pre, tt, code { 349 | font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 350 | font-size: 0.9em; 351 | } 352 | 353 | .hll { 354 | background-color: #FFC; 355 | margin: 0 -12px; 356 | padding: 0 12px; 357 | display: block; 358 | } 359 | 360 | img.screenshot { 361 | } 362 | 363 | tt.descname, tt.descclassname, code.descname, code.descclassname { 364 | font-size: 0.95em; 365 | } 366 | 367 | tt.descname, code.descname { 368 | padding-right: 0.08em; 369 | } 370 | 371 | img.screenshot { 372 | -moz-box-shadow: 2px 2px 4px #EEE; 373 | -webkit-box-shadow: 2px 2px 4px #EEE; 374 | box-shadow: 2px 2px 4px #EEE; 375 | } 376 | 377 | table.docutils { 378 | border: 1px solid #888; 379 | -moz-box-shadow: 2px 2px 4px #EEE; 380 | -webkit-box-shadow: 2px 2px 4px #EEE; 381 | box-shadow: 2px 2px 4px #EEE; 382 | } 383 | 384 | table.docutils td, table.docutils th { 385 | border: 1px solid #888; 386 | padding: 0.25em 0.7em; 387 | } 388 | 389 | table.field-list, table.footnote { 390 | border: none; 391 | -moz-box-shadow: none; 392 | -webkit-box-shadow: none; 393 | box-shadow: none; 394 | } 395 | 396 | table.footnote { 397 | margin: 15px 0; 398 | width: 100%; 399 | border: 1px solid #EEE; 400 | background: #FDFDFD; 401 | font-size: 0.9em; 402 | } 403 | 404 | table.footnote + table.footnote { 405 | margin-top: -15px; 406 | border-top: none; 407 | } 408 | 409 | table.field-list th { 410 | padding: 0 0.8em 0 0; 411 | } 412 | 413 | table.field-list td { 414 | padding: 0; 415 | } 416 | 417 | table.field-list p { 418 | margin-bottom: 0.8em; 419 | } 420 | 421 | /* Cloned from 422 | * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 423 | */ 424 | .field-name { 425 | -moz-hyphens: manual; 426 | -ms-hyphens: manual; 427 | -webkit-hyphens: manual; 428 | hyphens: manual; 429 | } 430 | 431 | table.footnote td.label { 432 | width: .1px; 433 | padding: 0.3em 0 0.3em 0.5em; 434 | } 435 | 436 | table.footnote td { 437 | padding: 0.3em 0.5em; 438 | } 439 | 440 | dl { 441 | margin: 0; 442 | padding: 0; 443 | } 444 | 445 | dl dd { 446 | margin-left: 30px; 447 | } 448 | 449 | blockquote { 450 | margin: 0 0 0 30px; 451 | padding: 0; 452 | } 453 | 454 | ul, ol { 455 | /* Matches the 30px from the narrow-screen "li > ul" selector below */ 456 | margin: 10px 0 10px 30px; 457 | padding: 0; 458 | } 459 | 460 | pre { 461 | background: #EEE; 462 | padding: 7px 30px; 463 | margin: 15px 0px; 464 | line-height: 1.3em; 465 | } 466 | 467 | div.viewcode-block:target { 468 | background: #ffd; 469 | } 470 | 471 | dl pre, blockquote pre, li pre { 472 | margin-left: 0; 473 | padding-left: 30px; 474 | } 475 | 476 | tt, code { 477 | background-color: #ecf0f3; 478 | color: #222; 479 | /* padding: 1px 2px; */ 480 | } 481 | 482 | tt.xref, code.xref, a tt { 483 | background-color: #FBFBFB; 484 | border-bottom: 1px solid #fff; 485 | } 486 | 487 | a.reference { 488 | text-decoration: none; 489 | border-bottom: 1px dotted #004B6B; 490 | } 491 | 492 | /* Don't put an underline on images */ 493 | a.image-reference, a.image-reference:hover { 494 | border-bottom: none; 495 | } 496 | 497 | a.reference:hover { 498 | border-bottom: 1px solid #6D4100; 499 | } 500 | 501 | a.footnote-reference { 502 | text-decoration: none; 503 | font-size: 0.7em; 504 | vertical-align: top; 505 | border-bottom: 1px dotted #004B6B; 506 | } 507 | 508 | a.footnote-reference:hover { 509 | border-bottom: 1px solid #6D4100; 510 | } 511 | 512 | a:hover tt, a:hover code { 513 | background: #EEE; 514 | } 515 | 516 | 517 | @media screen and (max-width: 870px) { 518 | 519 | div.sphinxsidebar { 520 | display: none; 521 | } 522 | 523 | div.document { 524 | width: 100%; 525 | 526 | } 527 | 528 | div.documentwrapper { 529 | margin-left: 0; 530 | margin-top: 0; 531 | margin-right: 0; 532 | margin-bottom: 0; 533 | } 534 | 535 | div.bodywrapper { 536 | margin-top: 0; 537 | margin-right: 0; 538 | margin-bottom: 0; 539 | margin-left: 0; 540 | } 541 | 542 | ul { 543 | margin-left: 0; 544 | } 545 | 546 | li > ul { 547 | /* Matches the 30px from the "ul, ol" selector above */ 548 | margin-left: 30px; 549 | } 550 | 551 | .document { 552 | width: auto; 553 | } 554 | 555 | .footer { 556 | width: auto; 557 | } 558 | 559 | .bodywrapper { 560 | margin: 0; 561 | } 562 | 563 | .footer { 564 | width: auto; 565 | } 566 | 567 | .github { 568 | display: none; 569 | } 570 | 571 | 572 | } 573 | 574 | 575 | @media screen and (max-width: 875px) { 576 | 577 | body { 578 | margin: 0; 579 | padding: 20px 30px; 580 | } 581 | 582 | div.documentwrapper { 583 | float: none; 584 | background: #fff; 585 | } 586 | 587 | div.sphinxsidebar { 588 | display: block; 589 | float: none; 590 | width: 102.5%; 591 | margin: 50px -30px -20px -30px; 592 | padding: 10px 20px; 593 | background: #333; 594 | color: #FFF; 595 | } 596 | 597 | div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, 598 | div.sphinxsidebar h3 a { 599 | color: #fff; 600 | } 601 | 602 | div.sphinxsidebar a { 603 | color: #AAA; 604 | } 605 | 606 | div.sphinxsidebar p.logo { 607 | display: none; 608 | } 609 | 610 | div.document { 611 | width: 100%; 612 | margin: 0; 613 | } 614 | 615 | div.footer { 616 | display: none; 617 | } 618 | 619 | div.bodywrapper { 620 | margin: 0; 621 | } 622 | 623 | div.body { 624 | min-height: 0; 625 | padding: 0; 626 | } 627 | 628 | .rtd_doc_footer { 629 | display: none; 630 | } 631 | 632 | .document { 633 | width: auto; 634 | } 635 | 636 | .footer { 637 | width: auto; 638 | } 639 | 640 | .footer { 641 | width: auto; 642 | } 643 | 644 | .github { 645 | display: none; 646 | } 647 | } 648 | 649 | 650 | /* misc. */ 651 | 652 | .revsys-inline { 653 | display: none !important; 654 | } 655 | 656 | /* Make nested-list/multi-paragraph items look better in Releases changelog 657 | * pages. Without this, docutils' magical list fuckery causes inconsistent 658 | * formatting between different release sub-lists. 659 | */ 660 | div#changelog > div.section > ul > li > p:only-child { 661 | margin-bottom: 0; 662 | } 663 | 664 | /* Hide fugly table cell borders in ..bibliography:: directive output */ 665 | table.docutils.citation, table.docutils.citation td, table.docutils.citation th { 666 | border: none; 667 | /* Below needed in some edge cases; if not applied, bottom shadows appear */ 668 | -moz-box-shadow: none; 669 | -webkit-box-shadow: none; 670 | box-shadow: none; 671 | } 672 | 673 | 674 | /* relbar */ 675 | 676 | .related { 677 | line-height: 30px; 678 | width: 100%; 679 | font-size: 0.9rem; 680 | } 681 | 682 | .related.top { 683 | border-bottom: 1px solid #EEE; 684 | margin-bottom: 20px; 685 | } 686 | 687 | .related.bottom { 688 | border-top: 1px solid #EEE; 689 | } 690 | 691 | .related ul { 692 | padding: 0; 693 | margin: 0; 694 | list-style: none; 695 | } 696 | 697 | .related li { 698 | display: inline; 699 | } 700 | 701 | nav#rellinks { 702 | float: right; 703 | } 704 | 705 | nav#rellinks li + li:before { 706 | content: "|"; 707 | } 708 | 709 | nav#breadcrumbs li + li:before { 710 | content: "\00BB"; 711 | } 712 | 713 | /* Hide certain items when printing */ 714 | @media print { 715 | div.related { 716 | display: none; 717 | } 718 | } -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/basic.css: -------------------------------------------------------------------------------- 1 | /* 2 | * basic.css 3 | * ~~~~~~~~~ 4 | * 5 | * Sphinx stylesheet -- basic theme. 6 | * 7 | * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | /* -- main layout ----------------------------------------------------------- */ 13 | 14 | div.clearer { 15 | clear: both; 16 | } 17 | 18 | div.section::after { 19 | display: block; 20 | content: ''; 21 | clear: left; 22 | } 23 | 24 | /* -- relbar ---------------------------------------------------------------- */ 25 | 26 | div.related { 27 | width: 100%; 28 | font-size: 90%; 29 | } 30 | 31 | div.related h3 { 32 | display: none; 33 | } 34 | 35 | div.related ul { 36 | margin: 0; 37 | padding: 0 0 0 10px; 38 | list-style: none; 39 | } 40 | 41 | div.related li { 42 | display: inline; 43 | } 44 | 45 | div.related li.right { 46 | float: right; 47 | margin-right: 5px; 48 | } 49 | 50 | /* -- sidebar --------------------------------------------------------------- */ 51 | 52 | div.sphinxsidebarwrapper { 53 | padding: 10px 5px 0 10px; 54 | } 55 | 56 | div.sphinxsidebar { 57 | float: left; 58 | width: 230px; 59 | margin-left: -100%; 60 | font-size: 90%; 61 | word-wrap: break-word; 62 | overflow-wrap: break-word; 63 | } 64 | 65 | div.sphinxsidebar ul { 66 | list-style: none; 67 | } 68 | 69 | div.sphinxsidebar ul ul, 70 | div.sphinxsidebar ul.want-points { 71 | margin-left: 20px; 72 | list-style: square; 73 | } 74 | 75 | div.sphinxsidebar ul ul { 76 | margin-top: 0; 77 | margin-bottom: 0; 78 | } 79 | 80 | div.sphinxsidebar form { 81 | margin-top: 10px; 82 | } 83 | 84 | div.sphinxsidebar input { 85 | border: 1px solid #98dbcc; 86 | font-family: sans-serif; 87 | font-size: 1em; 88 | } 89 | 90 | div.sphinxsidebar #searchbox form.search { 91 | overflow: hidden; 92 | } 93 | 94 | div.sphinxsidebar #searchbox input[type="text"] { 95 | float: left; 96 | width: 80%; 97 | padding: 0.25em; 98 | box-sizing: border-box; 99 | } 100 | 101 | div.sphinxsidebar #searchbox input[type="submit"] { 102 | float: left; 103 | width: 20%; 104 | border-left: none; 105 | padding: 0.25em; 106 | box-sizing: border-box; 107 | } 108 | 109 | 110 | img { 111 | border: 0; 112 | max-width: 100%; 113 | } 114 | 115 | /* -- search page ----------------------------------------------------------- */ 116 | 117 | ul.search { 118 | margin: 10px 0 0 20px; 119 | padding: 0; 120 | } 121 | 122 | ul.search li { 123 | padding: 5px 0 5px 20px; 124 | background-image: url(file.png); 125 | background-repeat: no-repeat; 126 | background-position: 0 7px; 127 | } 128 | 129 | ul.search li a { 130 | font-weight: bold; 131 | } 132 | 133 | ul.search li p.context { 134 | color: #888; 135 | margin: 2px 0 0 30px; 136 | text-align: left; 137 | } 138 | 139 | ul.keywordmatches li.goodmatch a { 140 | font-weight: bold; 141 | } 142 | 143 | /* -- index page ------------------------------------------------------------ */ 144 | 145 | table.contentstable { 146 | width: 90%; 147 | margin-left: auto; 148 | margin-right: auto; 149 | } 150 | 151 | table.contentstable p.biglink { 152 | line-height: 150%; 153 | } 154 | 155 | a.biglink { 156 | font-size: 1.3em; 157 | } 158 | 159 | span.linkdescr { 160 | font-style: italic; 161 | padding-top: 5px; 162 | font-size: 90%; 163 | } 164 | 165 | /* -- general index --------------------------------------------------------- */ 166 | 167 | table.indextable { 168 | width: 100%; 169 | } 170 | 171 | table.indextable td { 172 | text-align: left; 173 | vertical-align: top; 174 | } 175 | 176 | table.indextable ul { 177 | margin-top: 0; 178 | margin-bottom: 0; 179 | list-style-type: none; 180 | } 181 | 182 | table.indextable > tbody > tr > td > ul { 183 | padding-left: 0em; 184 | } 185 | 186 | table.indextable tr.pcap { 187 | height: 10px; 188 | } 189 | 190 | table.indextable tr.cap { 191 | margin-top: 10px; 192 | background-color: #f2f2f2; 193 | } 194 | 195 | img.toggler { 196 | margin-right: 3px; 197 | margin-top: 3px; 198 | cursor: pointer; 199 | } 200 | 201 | div.modindex-jumpbox { 202 | border-top: 1px solid #ddd; 203 | border-bottom: 1px solid #ddd; 204 | margin: 1em 0 1em 0; 205 | padding: 0.4em; 206 | } 207 | 208 | div.genindex-jumpbox { 209 | border-top: 1px solid #ddd; 210 | border-bottom: 1px solid #ddd; 211 | margin: 1em 0 1em 0; 212 | padding: 0.4em; 213 | } 214 | 215 | /* -- domain module index --------------------------------------------------- */ 216 | 217 | table.modindextable td { 218 | padding: 2px; 219 | border-collapse: collapse; 220 | } 221 | 222 | /* -- general body styles --------------------------------------------------- */ 223 | 224 | div.body { 225 | min-width: 360px; 226 | max-width: 800px; 227 | } 228 | 229 | div.body p, div.body dd, div.body li, div.body blockquote { 230 | -moz-hyphens: auto; 231 | -ms-hyphens: auto; 232 | -webkit-hyphens: auto; 233 | hyphens: auto; 234 | } 235 | 236 | a.headerlink { 237 | visibility: hidden; 238 | } 239 | 240 | h1:hover > a.headerlink, 241 | h2:hover > a.headerlink, 242 | h3:hover > a.headerlink, 243 | h4:hover > a.headerlink, 244 | h5:hover > a.headerlink, 245 | h6:hover > a.headerlink, 246 | dt:hover > a.headerlink, 247 | caption:hover > a.headerlink, 248 | p.caption:hover > a.headerlink, 249 | div.code-block-caption:hover > a.headerlink { 250 | visibility: visible; 251 | } 252 | 253 | div.body p.caption { 254 | text-align: inherit; 255 | } 256 | 257 | div.body td { 258 | text-align: left; 259 | } 260 | 261 | .first { 262 | margin-top: 0 !important; 263 | } 264 | 265 | p.rubric { 266 | margin-top: 30px; 267 | font-weight: bold; 268 | } 269 | 270 | img.align-left, figure.align-left, .figure.align-left, object.align-left { 271 | clear: left; 272 | float: left; 273 | margin-right: 1em; 274 | } 275 | 276 | img.align-right, figure.align-right, .figure.align-right, object.align-right { 277 | clear: right; 278 | float: right; 279 | margin-left: 1em; 280 | } 281 | 282 | img.align-center, figure.align-center, .figure.align-center, object.align-center { 283 | display: block; 284 | margin-left: auto; 285 | margin-right: auto; 286 | } 287 | 288 | img.align-default, figure.align-default, .figure.align-default { 289 | display: block; 290 | margin-left: auto; 291 | margin-right: auto; 292 | } 293 | 294 | .align-left { 295 | text-align: left; 296 | } 297 | 298 | .align-center { 299 | text-align: center; 300 | } 301 | 302 | .align-default { 303 | text-align: center; 304 | } 305 | 306 | .align-right { 307 | text-align: right; 308 | } 309 | 310 | /* -- sidebars -------------------------------------------------------------- */ 311 | 312 | div.sidebar, 313 | aside.sidebar { 314 | margin: 0 0 0.5em 1em; 315 | border: 1px solid #ddb; 316 | padding: 7px; 317 | background-color: #ffe; 318 | width: 40%; 319 | float: right; 320 | clear: right; 321 | overflow-x: auto; 322 | } 323 | 324 | p.sidebar-title { 325 | font-weight: bold; 326 | } 327 | 328 | nav.contents, 329 | aside.topic, 330 | div.admonition, div.topic, blockquote { 331 | clear: left; 332 | } 333 | 334 | /* -- topics ---------------------------------------------------------------- */ 335 | nav.contents, 336 | aside.topic, 337 | div.topic { 338 | border: 1px solid #ccc; 339 | padding: 7px; 340 | margin: 10px 0 10px 0; 341 | } 342 | 343 | p.topic-title { 344 | font-size: 1.1em; 345 | font-weight: bold; 346 | margin-top: 10px; 347 | } 348 | 349 | /* -- admonitions ----------------------------------------------------------- */ 350 | 351 | div.admonition { 352 | margin-top: 10px; 353 | margin-bottom: 10px; 354 | padding: 7px; 355 | } 356 | 357 | div.admonition dt { 358 | font-weight: bold; 359 | } 360 | 361 | p.admonition-title { 362 | margin: 0px 10px 5px 0px; 363 | font-weight: bold; 364 | } 365 | 366 | div.body p.centered { 367 | text-align: center; 368 | margin-top: 25px; 369 | } 370 | 371 | /* -- content of sidebars/topics/admonitions -------------------------------- */ 372 | 373 | div.sidebar > :last-child, 374 | aside.sidebar > :last-child, 375 | nav.contents > :last-child, 376 | aside.topic > :last-child, 377 | div.topic > :last-child, 378 | div.admonition > :last-child { 379 | margin-bottom: 0; 380 | } 381 | 382 | div.sidebar::after, 383 | aside.sidebar::after, 384 | nav.contents::after, 385 | aside.topic::after, 386 | div.topic::after, 387 | div.admonition::after, 388 | blockquote::after { 389 | display: block; 390 | content: ''; 391 | clear: both; 392 | } 393 | 394 | /* -- tables ---------------------------------------------------------------- */ 395 | 396 | table.docutils { 397 | margin-top: 10px; 398 | margin-bottom: 10px; 399 | border: 0; 400 | border-collapse: collapse; 401 | } 402 | 403 | table.align-center { 404 | margin-left: auto; 405 | margin-right: auto; 406 | } 407 | 408 | table.align-default { 409 | margin-left: auto; 410 | margin-right: auto; 411 | } 412 | 413 | table caption span.caption-number { 414 | font-style: italic; 415 | } 416 | 417 | table caption span.caption-text { 418 | } 419 | 420 | table.docutils td, table.docutils th { 421 | padding: 1px 8px 1px 5px; 422 | border-top: 0; 423 | border-left: 0; 424 | border-right: 0; 425 | border-bottom: 1px solid #aaa; 426 | } 427 | 428 | th { 429 | text-align: left; 430 | padding-right: 5px; 431 | } 432 | 433 | table.citation { 434 | border-left: solid 1px gray; 435 | margin-left: 1px; 436 | } 437 | 438 | table.citation td { 439 | border-bottom: none; 440 | } 441 | 442 | th > :first-child, 443 | td > :first-child { 444 | margin-top: 0px; 445 | } 446 | 447 | th > :last-child, 448 | td > :last-child { 449 | margin-bottom: 0px; 450 | } 451 | 452 | /* -- figures --------------------------------------------------------------- */ 453 | 454 | div.figure, figure { 455 | margin: 0.5em; 456 | padding: 0.5em; 457 | } 458 | 459 | div.figure p.caption, figcaption { 460 | padding: 0.3em; 461 | } 462 | 463 | div.figure p.caption span.caption-number, 464 | figcaption span.caption-number { 465 | font-style: italic; 466 | } 467 | 468 | div.figure p.caption span.caption-text, 469 | figcaption span.caption-text { 470 | } 471 | 472 | /* -- field list styles ----------------------------------------------------- */ 473 | 474 | table.field-list td, table.field-list th { 475 | border: 0 !important; 476 | } 477 | 478 | .field-list ul { 479 | margin: 0; 480 | padding-left: 1em; 481 | } 482 | 483 | .field-list p { 484 | margin: 0; 485 | } 486 | 487 | .field-name { 488 | -moz-hyphens: manual; 489 | -ms-hyphens: manual; 490 | -webkit-hyphens: manual; 491 | hyphens: manual; 492 | } 493 | 494 | /* -- hlist styles ---------------------------------------------------------- */ 495 | 496 | table.hlist { 497 | margin: 1em 0; 498 | } 499 | 500 | table.hlist td { 501 | vertical-align: top; 502 | } 503 | 504 | /* -- object description styles --------------------------------------------- */ 505 | 506 | .sig { 507 | font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 508 | } 509 | 510 | .sig-name, code.descname { 511 | background-color: transparent; 512 | font-weight: bold; 513 | } 514 | 515 | .sig-name { 516 | font-size: 1.1em; 517 | } 518 | 519 | code.descname { 520 | font-size: 1.2em; 521 | } 522 | 523 | .sig-prename, code.descclassname { 524 | background-color: transparent; 525 | } 526 | 527 | .optional { 528 | font-size: 1.3em; 529 | } 530 | 531 | .sig-paren { 532 | font-size: larger; 533 | } 534 | 535 | .sig-param.n { 536 | font-style: italic; 537 | } 538 | 539 | /* C++ specific styling */ 540 | 541 | .sig-inline.c-texpr, 542 | .sig-inline.cpp-texpr { 543 | font-family: unset; 544 | } 545 | 546 | .sig.c .k, .sig.c .kt, 547 | .sig.cpp .k, .sig.cpp .kt { 548 | color: #0033B3; 549 | } 550 | 551 | .sig.c .m, 552 | .sig.cpp .m { 553 | color: #1750EB; 554 | } 555 | 556 | .sig.c .s, .sig.c .sc, 557 | .sig.cpp .s, .sig.cpp .sc { 558 | color: #067D17; 559 | } 560 | 561 | 562 | /* -- other body styles ----------------------------------------------------- */ 563 | 564 | ol.arabic { 565 | list-style: decimal; 566 | } 567 | 568 | ol.loweralpha { 569 | list-style: lower-alpha; 570 | } 571 | 572 | ol.upperalpha { 573 | list-style: upper-alpha; 574 | } 575 | 576 | ol.lowerroman { 577 | list-style: lower-roman; 578 | } 579 | 580 | ol.upperroman { 581 | list-style: upper-roman; 582 | } 583 | 584 | :not(li) > ol > li:first-child > :first-child, 585 | :not(li) > ul > li:first-child > :first-child { 586 | margin-top: 0px; 587 | } 588 | 589 | :not(li) > ol > li:last-child > :last-child, 590 | :not(li) > ul > li:last-child > :last-child { 591 | margin-bottom: 0px; 592 | } 593 | 594 | ol.simple ol p, 595 | ol.simple ul p, 596 | ul.simple ol p, 597 | ul.simple ul p { 598 | margin-top: 0; 599 | } 600 | 601 | ol.simple > li:not(:first-child) > p, 602 | ul.simple > li:not(:first-child) > p { 603 | margin-top: 0; 604 | } 605 | 606 | ol.simple p, 607 | ul.simple p { 608 | margin-bottom: 0; 609 | } 610 | 611 | aside.footnote > span, 612 | div.citation > span { 613 | float: left; 614 | } 615 | 616 | aside.footnote > span:last-of-type, 617 | div.citation > span:last-of-type { 618 | padding-right: 0.5em; 619 | } 620 | 621 | aside.footnote > p { 622 | margin-left: 2em; 623 | } 624 | 625 | div.citation > p { 626 | margin-left: 4em; 627 | } 628 | 629 | aside.footnote > p:last-of-type, 630 | div.citation > p:last-of-type { 631 | margin-bottom: 0em; 632 | } 633 | 634 | aside.footnote > p:last-of-type:after, 635 | div.citation > p:last-of-type:after { 636 | content: ""; 637 | clear: both; 638 | } 639 | 640 | dl.field-list { 641 | display: grid; 642 | grid-template-columns: fit-content(30%) auto; 643 | } 644 | 645 | dl.field-list > dt { 646 | font-weight: bold; 647 | word-break: break-word; 648 | padding-left: 0.5em; 649 | padding-right: 5px; 650 | } 651 | 652 | dl.field-list > dd { 653 | padding-left: 0.5em; 654 | margin-top: 0em; 655 | margin-left: 0em; 656 | margin-bottom: 0em; 657 | } 658 | 659 | dl { 660 | margin-bottom: 15px; 661 | } 662 | 663 | dd > :first-child { 664 | margin-top: 0px; 665 | } 666 | 667 | dd ul, dd table { 668 | margin-bottom: 10px; 669 | } 670 | 671 | dd { 672 | margin-top: 3px; 673 | margin-bottom: 10px; 674 | margin-left: 30px; 675 | } 676 | 677 | dl > dd:last-child, 678 | dl > dd:last-child > :last-child { 679 | margin-bottom: 0; 680 | } 681 | 682 | dt:target, span.highlighted { 683 | background-color: #fbe54e; 684 | } 685 | 686 | rect.highlighted { 687 | fill: #fbe54e; 688 | } 689 | 690 | dl.glossary dt { 691 | font-weight: bold; 692 | font-size: 1.1em; 693 | } 694 | 695 | .versionmodified { 696 | font-style: italic; 697 | } 698 | 699 | .system-message { 700 | background-color: #fda; 701 | padding: 5px; 702 | border: 3px solid red; 703 | } 704 | 705 | .footnote:target { 706 | background-color: #ffa; 707 | } 708 | 709 | .line-block { 710 | display: block; 711 | margin-top: 1em; 712 | margin-bottom: 1em; 713 | } 714 | 715 | .line-block .line-block { 716 | margin-top: 0; 717 | margin-bottom: 0; 718 | margin-left: 1.5em; 719 | } 720 | 721 | .guilabel, .menuselection { 722 | font-family: sans-serif; 723 | } 724 | 725 | .accelerator { 726 | text-decoration: underline; 727 | } 728 | 729 | .classifier { 730 | font-style: oblique; 731 | } 732 | 733 | .classifier:before { 734 | font-style: normal; 735 | margin: 0 0.5em; 736 | content: ":"; 737 | display: inline-block; 738 | } 739 | 740 | abbr, acronym { 741 | border-bottom: dotted 1px; 742 | cursor: help; 743 | } 744 | 745 | /* -- code displays --------------------------------------------------------- */ 746 | 747 | pre { 748 | overflow: auto; 749 | overflow-y: hidden; /* fixes display issues on Chrome browsers */ 750 | } 751 | 752 | pre, div[class*="highlight-"] { 753 | clear: both; 754 | } 755 | 756 | span.pre { 757 | -moz-hyphens: none; 758 | -ms-hyphens: none; 759 | -webkit-hyphens: none; 760 | hyphens: none; 761 | white-space: nowrap; 762 | } 763 | 764 | div[class*="highlight-"] { 765 | margin: 1em 0; 766 | } 767 | 768 | td.linenos pre { 769 | border: 0; 770 | background-color: transparent; 771 | color: #aaa; 772 | } 773 | 774 | table.highlighttable { 775 | display: block; 776 | } 777 | 778 | table.highlighttable tbody { 779 | display: block; 780 | } 781 | 782 | table.highlighttable tr { 783 | display: flex; 784 | } 785 | 786 | table.highlighttable td { 787 | margin: 0; 788 | padding: 0; 789 | } 790 | 791 | table.highlighttable td.linenos { 792 | padding-right: 0.5em; 793 | } 794 | 795 | table.highlighttable td.code { 796 | flex: 1; 797 | overflow: hidden; 798 | } 799 | 800 | .highlight .hll { 801 | display: block; 802 | } 803 | 804 | div.highlight pre, 805 | table.highlighttable pre { 806 | margin: 0; 807 | } 808 | 809 | div.code-block-caption + div { 810 | margin-top: 0; 811 | } 812 | 813 | div.code-block-caption { 814 | margin-top: 1em; 815 | padding: 2px 5px; 816 | font-size: small; 817 | } 818 | 819 | div.code-block-caption code { 820 | background-color: transparent; 821 | } 822 | 823 | table.highlighttable td.linenos, 824 | span.linenos, 825 | div.highlight span.gp { /* gp: Generic.Prompt */ 826 | user-select: none; 827 | -webkit-user-select: text; /* Safari fallback only */ 828 | -webkit-user-select: none; /* Chrome/Safari */ 829 | -moz-user-select: none; /* Firefox */ 830 | -ms-user-select: none; /* IE10+ */ 831 | } 832 | 833 | div.code-block-caption span.caption-number { 834 | padding: 0.1em 0.3em; 835 | font-style: italic; 836 | } 837 | 838 | div.code-block-caption span.caption-text { 839 | } 840 | 841 | div.literal-block-wrapper { 842 | margin: 1em 0; 843 | } 844 | 845 | code.xref, a code { 846 | background-color: transparent; 847 | font-weight: bold; 848 | } 849 | 850 | h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { 851 | background-color: transparent; 852 | } 853 | 854 | .viewcode-link { 855 | float: right; 856 | } 857 | 858 | .viewcode-back { 859 | float: right; 860 | font-family: sans-serif; 861 | } 862 | 863 | div.viewcode-block:target { 864 | margin: -1px -10px; 865 | padding: 0 10px; 866 | } 867 | 868 | /* -- math display ---------------------------------------------------------- */ 869 | 870 | img.math { 871 | vertical-align: middle; 872 | } 873 | 874 | div.body div.math p { 875 | text-align: center; 876 | } 877 | 878 | span.eqno { 879 | float: right; 880 | } 881 | 882 | span.eqno a.headerlink { 883 | position: absolute; 884 | z-index: 1; 885 | } 886 | 887 | div.math:hover a.headerlink { 888 | visibility: visible; 889 | } 890 | 891 | /* -- printout stylesheet --------------------------------------------------- */ 892 | 893 | @media print { 894 | div.document, 895 | div.documentwrapper, 896 | div.bodywrapper { 897 | margin: 0 !important; 898 | width: 100%; 899 | } 900 | 901 | div.sphinxsidebar, 902 | div.related, 903 | div.footer, 904 | #top-link { 905 | display: none; 906 | } 907 | } -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* This file intentionally left blank. */ 2 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * doctools.js 3 | * ~~~~~~~~~~~ 4 | * 5 | * Base JavaScript utilities for all Sphinx HTML documentation. 6 | * 7 | * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | "use strict"; 12 | 13 | const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ 14 | "TEXTAREA", 15 | "INPUT", 16 | "SELECT", 17 | "BUTTON", 18 | ]); 19 | 20 | const _ready = (callback) => { 21 | if (document.readyState !== "loading") { 22 | callback(); 23 | } else { 24 | document.addEventListener("DOMContentLoaded", callback); 25 | } 26 | }; 27 | 28 | /** 29 | * Small JavaScript module for the documentation. 30 | */ 31 | const Documentation = { 32 | init: () => { 33 | Documentation.initDomainIndexTable(); 34 | Documentation.initOnKeyListeners(); 35 | }, 36 | 37 | /** 38 | * i18n support 39 | */ 40 | TRANSLATIONS: {}, 41 | PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), 42 | LOCALE: "unknown", 43 | 44 | // gettext and ngettext don't access this so that the functions 45 | // can safely bound to a different name (_ = Documentation.gettext) 46 | gettext: (string) => { 47 | const translated = Documentation.TRANSLATIONS[string]; 48 | switch (typeof translated) { 49 | case "undefined": 50 | return string; // no translation 51 | case "string": 52 | return translated; // translation exists 53 | default: 54 | return translated[0]; // (singular, plural) translation tuple exists 55 | } 56 | }, 57 | 58 | ngettext: (singular, plural, n) => { 59 | const translated = Documentation.TRANSLATIONS[singular]; 60 | if (typeof translated !== "undefined") 61 | return translated[Documentation.PLURAL_EXPR(n)]; 62 | return n === 1 ? singular : plural; 63 | }, 64 | 65 | addTranslations: (catalog) => { 66 | Object.assign(Documentation.TRANSLATIONS, catalog.messages); 67 | Documentation.PLURAL_EXPR = new Function( 68 | "n", 69 | `return (${catalog.plural_expr})` 70 | ); 71 | Documentation.LOCALE = catalog.locale; 72 | }, 73 | 74 | /** 75 | * helper function to focus on search bar 76 | */ 77 | focusSearchBar: () => { 78 | document.querySelectorAll("input[name=q]")[0]?.focus(); 79 | }, 80 | 81 | /** 82 | * Initialise the domain index toggle buttons 83 | */ 84 | initDomainIndexTable: () => { 85 | const toggler = (el) => { 86 | const idNumber = el.id.substr(7); 87 | const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); 88 | if (el.src.substr(-9) === "minus.png") { 89 | el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; 90 | toggledRows.forEach((el) => (el.style.display = "none")); 91 | } else { 92 | el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; 93 | toggledRows.forEach((el) => (el.style.display = "")); 94 | } 95 | }; 96 | 97 | const togglerElements = document.querySelectorAll("img.toggler"); 98 | togglerElements.forEach((el) => 99 | el.addEventListener("click", (event) => toggler(event.currentTarget)) 100 | ); 101 | togglerElements.forEach((el) => (el.style.display = "")); 102 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); 103 | }, 104 | 105 | initOnKeyListeners: () => { 106 | // only install a listener if it is really needed 107 | if ( 108 | !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && 109 | !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS 110 | ) 111 | return; 112 | 113 | document.addEventListener("keydown", (event) => { 114 | // bail for input elements 115 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 116 | // bail with special keys 117 | if (event.altKey || event.ctrlKey || event.metaKey) return; 118 | 119 | if (!event.shiftKey) { 120 | switch (event.key) { 121 | case "ArrowLeft": 122 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 123 | 124 | const prevLink = document.querySelector('link[rel="prev"]'); 125 | if (prevLink && prevLink.href) { 126 | window.location.href = prevLink.href; 127 | event.preventDefault(); 128 | } 129 | break; 130 | case "ArrowRight": 131 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 132 | 133 | const nextLink = document.querySelector('link[rel="next"]'); 134 | if (nextLink && nextLink.href) { 135 | window.location.href = nextLink.href; 136 | event.preventDefault(); 137 | } 138 | break; 139 | } 140 | } 141 | 142 | // some keyboard layouts may need Shift to get / 143 | switch (event.key) { 144 | case "/": 145 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; 146 | Documentation.focusSearchBar(); 147 | event.preventDefault(); 148 | } 149 | }); 150 | }, 151 | }; 152 | 153 | // quick alias for translations 154 | const _ = Documentation.gettext; 155 | 156 | _ready(Documentation.init); 157 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | var DOCUMENTATION_OPTIONS = { 2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), 3 | VERSION: '0.0.1', 4 | LANGUAGE: 'en', 5 | COLLAPSE_INDEX: false, 6 | BUILDER: 'html', 7 | FILE_SUFFIX: '.html', 8 | LINK_SUFFIX: '.html', 9 | HAS_SOURCE: true, 10 | SOURCELINK_SUFFIX: '.txt', 11 | NAVIGATION_WITH_KEYS: false, 12 | SHOW_SEARCH_SUMMARY: true, 13 | ENABLE_SEARCH_SHORTCUTS: true, 14 | }; -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/hftcryptoapi/bitmart/docs/build/html/_static/file.png -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/language_data.js: -------------------------------------------------------------------------------- 1 | /* 2 | * language_data.js 3 | * ~~~~~~~~~~~~~~~~ 4 | * 5 | * This script contains the language-specific data used by searchtools.js, 6 | * namely the list of stopwords, stemmer, scorer and splitter. 7 | * 8 | * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. 9 | * :license: BSD, see LICENSE for details. 10 | * 11 | */ 12 | 13 | var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; 14 | 15 | 16 | /* Non-minified version is copied as a separate JS file, is available */ 17 | 18 | /** 19 | * Porter Stemmer 20 | */ 21 | var Stemmer = function () { 22 | 23 | var step2list = { 24 | ational: 'ate', 25 | tional: 'tion', 26 | enci: 'ence', 27 | anci: 'ance', 28 | izer: 'ize', 29 | bli: 'ble', 30 | alli: 'al', 31 | entli: 'ent', 32 | eli: 'e', 33 | ousli: 'ous', 34 | ization: 'ize', 35 | ation: 'ate', 36 | ator: 'ate', 37 | alism: 'al', 38 | iveness: 'ive', 39 | fulness: 'ful', 40 | ousness: 'ous', 41 | aliti: 'al', 42 | iviti: 'ive', 43 | biliti: 'ble', 44 | logi: 'log' 45 | }; 46 | 47 | var step3list = { 48 | icate: 'ic', 49 | ative: '', 50 | alize: 'al', 51 | iciti: 'ic', 52 | ical: 'ic', 53 | ful: '', 54 | ness: '' 55 | }; 56 | 57 | var c = "[^aeiou]"; // consonant 58 | var v = "[aeiouy]"; // vowel 59 | var C = c + "[^aeiouy]*"; // consonant sequence 60 | var V = v + "[aeiou]*"; // vowel sequence 61 | 62 | var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 63 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 64 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 65 | var s_v = "^(" + C + ")?" + v; // vowel in stem 66 | 67 | this.stemWord = function (w) { 68 | var stem; 69 | var suffix; 70 | var firstch; 71 | var origword = w; 72 | 73 | if (w.length < 3) 74 | return w; 75 | 76 | var re; 77 | var re2; 78 | var re3; 79 | var re4; 80 | 81 | firstch = w.substr(0, 1); 82 | if (firstch == "y") 83 | w = firstch.toUpperCase() + w.substr(1); 84 | 85 | // Step 1a 86 | re = /^(.+?)(ss|i)es$/; 87 | re2 = /^(.+?)([^s])s$/; 88 | 89 | if (re.test(w)) 90 | w = w.replace(re, "$1$2"); 91 | else if (re2.test(w)) 92 | w = w.replace(re2, "$1$2"); 93 | 94 | // Step 1b 95 | re = /^(.+?)eed$/; 96 | re2 = /^(.+?)(ed|ing)$/; 97 | if (re.test(w)) { 98 | var fp = re.exec(w); 99 | re = new RegExp(mgr0); 100 | if (re.test(fp[1])) { 101 | re = /.$/; 102 | w = w.replace(re, ""); 103 | } 104 | } else if (re2.test(w)) { 105 | var fp = re2.exec(w); 106 | stem = fp[1]; 107 | re2 = new RegExp(s_v); 108 | if (re2.test(stem)) { 109 | w = stem; 110 | re2 = /(at|bl|iz)$/; 111 | re3 = new RegExp("([^aeiouylsz])\\1$"); 112 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 113 | if (re2.test(w)) 114 | w = w + "e"; 115 | else if (re3.test(w)) { 116 | re = /.$/; 117 | w = w.replace(re, ""); 118 | } else if (re4.test(w)) 119 | w = w + "e"; 120 | } 121 | } 122 | 123 | // Step 1c 124 | re = /^(.+?)y$/; 125 | if (re.test(w)) { 126 | var fp = re.exec(w); 127 | stem = fp[1]; 128 | re = new RegExp(s_v); 129 | if (re.test(stem)) 130 | w = stem + "i"; 131 | } 132 | 133 | // Step 2 134 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; 135 | if (re.test(w)) { 136 | var fp = re.exec(w); 137 | stem = fp[1]; 138 | suffix = fp[2]; 139 | re = new RegExp(mgr0); 140 | if (re.test(stem)) 141 | w = stem + step2list[suffix]; 142 | } 143 | 144 | // Step 3 145 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; 146 | if (re.test(w)) { 147 | var fp = re.exec(w); 148 | stem = fp[1]; 149 | suffix = fp[2]; 150 | re = new RegExp(mgr0); 151 | if (re.test(stem)) 152 | w = stem + step3list[suffix]; 153 | } 154 | 155 | // Step 4 156 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; 157 | re2 = /^(.+?)(s|t)(ion)$/; 158 | if (re.test(w)) { 159 | var fp = re.exec(w); 160 | stem = fp[1]; 161 | re = new RegExp(mgr1); 162 | if (re.test(stem)) 163 | w = stem; 164 | } else if (re2.test(w)) { 165 | var fp = re2.exec(w); 166 | stem = fp[1] + fp[2]; 167 | re2 = new RegExp(mgr1); 168 | if (re2.test(stem)) 169 | w = stem; 170 | } 171 | 172 | // Step 5 173 | re = /^(.+?)e$/; 174 | if (re.test(w)) { 175 | var fp = re.exec(w); 176 | stem = fp[1]; 177 | re = new RegExp(mgr1); 178 | re2 = new RegExp(meq1); 179 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 180 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) 181 | w = stem; 182 | } 183 | re = /ll$/; 184 | re2 = new RegExp(mgr1); 185 | if (re.test(w) && re2.test(w)) { 186 | re = /.$/; 187 | w = w.replace(re, ""); 188 | } 189 | 190 | // and turn initial Y back to y 191 | if (firstch == "y") 192 | w = firstch.toLowerCase() + w.substr(1); 193 | return w; 194 | } 195 | } 196 | 197 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/hftcryptoapi/bitmart/docs/build/html/_static/minus.png -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/hftcryptoapi/bitmart/docs/build/html/_static/plus.png -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | pre { 2 | line-height: 125%; 3 | } 4 | 5 | td.linenos .normal { 6 | color: inherit; 7 | background-color: transparent; 8 | padding-left: 5px; 9 | padding-right: 5px; 10 | } 11 | 12 | span.linenos { 13 | color: inherit; 14 | background-color: transparent; 15 | padding-left: 5px; 16 | padding-right: 5px; 17 | } 18 | 19 | td.linenos .special { 20 | color: #000000; 21 | background-color: #ffffc0; 22 | padding-left: 5px; 23 | padding-right: 5px; 24 | } 25 | 26 | span.linenos.special { 27 | color: #000000; 28 | background-color: #ffffc0; 29 | padding-left: 5px; 30 | padding-right: 5px; 31 | } 32 | 33 | .highlight .hll { 34 | background-color: #ffffcc 35 | } 36 | 37 | .highlight { 38 | background: #f8f8f8; 39 | } 40 | 41 | .highlight .c { 42 | color: #8f5902; 43 | font-style: italic 44 | } 45 | 46 | /* Comment */ 47 | .highlight .err { 48 | color: #a40000; 49 | border: 1px solid #ef2929 50 | } 51 | 52 | /* Error */ 53 | .highlight .g { 54 | color: #000000 55 | } 56 | 57 | /* Generic */ 58 | .highlight .k { 59 | color: #004461; 60 | font-weight: bold 61 | } 62 | 63 | /* Keyword */ 64 | .highlight .l { 65 | color: #000000 66 | } 67 | 68 | /* Literal */ 69 | .highlight .n { 70 | color: #000000 71 | } 72 | 73 | /* Name */ 74 | .highlight .o { 75 | color: #582800 76 | } 77 | 78 | /* Operator */ 79 | .highlight .x { 80 | color: #000000 81 | } 82 | 83 | /* Other */ 84 | .highlight .p { 85 | color: #000000; 86 | font-weight: bold 87 | } 88 | 89 | /* Punctuation */ 90 | .highlight .ch { 91 | color: #8f5902; 92 | font-style: italic 93 | } 94 | 95 | /* Comment.Hashbang */ 96 | .highlight .cm { 97 | color: #8f5902; 98 | font-style: italic 99 | } 100 | 101 | /* Comment.Multiline */ 102 | .highlight .cp { 103 | color: #8f5902 104 | } 105 | 106 | /* Comment.Preproc */ 107 | .highlight .cpf { 108 | color: #8f5902; 109 | font-style: italic 110 | } 111 | 112 | /* Comment.PreprocFile */ 113 | .highlight .c1 { 114 | color: #8f5902; 115 | font-style: italic 116 | } 117 | 118 | /* Comment.Single */ 119 | .highlight .cs { 120 | color: #8f5902; 121 | font-style: italic 122 | } 123 | 124 | /* Comment.Special */ 125 | .highlight .gd { 126 | color: #a40000 127 | } 128 | 129 | /* Generic.Deleted */ 130 | .highlight .ge { 131 | color: #000000; 132 | font-style: italic 133 | } 134 | 135 | /* Generic.Emph */ 136 | .highlight .gr { 137 | color: #ef2929 138 | } 139 | 140 | /* Generic.Error */ 141 | .highlight .gh { 142 | color: #000080; 143 | font-weight: bold 144 | } 145 | 146 | /* Generic.Heading */ 147 | .highlight .gi { 148 | color: #00A000 149 | } 150 | 151 | /* Generic.Inserted */ 152 | .highlight .go { 153 | color: #888888 154 | } 155 | 156 | /* Generic.Output */ 157 | .highlight .gp { 158 | color: #745334 159 | } 160 | 161 | /* Generic.Prompt */ 162 | .highlight .gs { 163 | color: #000000; 164 | font-weight: bold 165 | } 166 | 167 | /* Generic.Strong */ 168 | .highlight .gu { 169 | color: #800080; 170 | font-weight: bold 171 | } 172 | 173 | /* Generic.Subheading */ 174 | .highlight .gt { 175 | color: #a40000; 176 | font-weight: bold 177 | } 178 | 179 | /* Generic.Traceback */ 180 | .highlight .kc { 181 | color: #004461; 182 | font-weight: bold 183 | } 184 | 185 | /* Keyword.Constant */ 186 | .highlight .kd { 187 | color: #004461; 188 | font-weight: bold 189 | } 190 | 191 | /* Keyword.Declaration */ 192 | .highlight .kn { 193 | color: #004461; 194 | font-weight: bold 195 | } 196 | 197 | /* Keyword.Namespace */ 198 | .highlight .kp { 199 | color: #004461; 200 | font-weight: bold 201 | } 202 | 203 | /* Keyword.Pseudo */ 204 | .highlight .kr { 205 | color: #004461; 206 | font-weight: bold 207 | } 208 | 209 | /* Keyword.Reserved */ 210 | .highlight .kt { 211 | color: #004461; 212 | font-weight: bold 213 | } 214 | 215 | /* Keyword.Type */ 216 | .highlight .ld { 217 | color: #000000 218 | } 219 | 220 | /* Literal.Date */ 221 | .highlight .m { 222 | color: #990000 223 | } 224 | 225 | /* Literal.Number */ 226 | .highlight .s { 227 | color: #4e9a06 228 | } 229 | 230 | /* Literal.String */ 231 | .highlight .na { 232 | color: #c4a000 233 | } 234 | 235 | /* Name.Attribute */ 236 | .highlight .nb { 237 | color: #004461 238 | } 239 | 240 | /* Name.Builtin */ 241 | .highlight .nc { 242 | color: #000000 243 | } 244 | 245 | /* Name.Class */ 246 | .highlight .no { 247 | color: #000000 248 | } 249 | 250 | /* Name.Constant */ 251 | .highlight .nd { 252 | color: #888888 253 | } 254 | 255 | /* Name.Decorator */ 256 | .highlight .ni { 257 | color: #ce5c00 258 | } 259 | 260 | /* Name.Entity */ 261 | .highlight .ne { 262 | color: #cc0000; 263 | font-weight: bold 264 | } 265 | 266 | /* Name.Exception */ 267 | .highlight .nf { 268 | color: #000000 269 | } 270 | 271 | /* Name.Function */ 272 | .highlight .nl { 273 | color: #f57900 274 | } 275 | 276 | /* Name.Label */ 277 | .highlight .nn { 278 | color: #000000 279 | } 280 | 281 | /* Name.Namespace */ 282 | .highlight .nx { 283 | color: #000000 284 | } 285 | 286 | /* Name.Other */ 287 | .highlight .py { 288 | color: #000000 289 | } 290 | 291 | /* Name.Property */ 292 | .highlight .nt { 293 | color: #004461; 294 | font-weight: bold 295 | } 296 | 297 | /* Name.Tag */ 298 | .highlight .nv { 299 | color: #000000 300 | } 301 | 302 | /* Name.Variable */ 303 | .highlight .ow { 304 | color: #004461; 305 | font-weight: bold 306 | } 307 | 308 | /* Operator.Word */ 309 | .highlight .pm { 310 | color: #000000; 311 | font-weight: bold 312 | } 313 | 314 | /* Punctuation.Marker */ 315 | .highlight .w { 316 | color: #f8f8f8; 317 | text-decoration: underline 318 | } 319 | 320 | /* Text.Whitespace */ 321 | .highlight .mb { 322 | color: #990000 323 | } 324 | 325 | /* Literal.Number.Bin */ 326 | .highlight .mf { 327 | color: #990000 328 | } 329 | 330 | /* Literal.Number.Float */ 331 | .highlight .mh { 332 | color: #990000 333 | } 334 | 335 | /* Literal.Number.Hex */ 336 | .highlight .mi { 337 | color: #990000 338 | } 339 | 340 | /* Literal.Number.Integer */ 341 | .highlight .mo { 342 | color: #990000 343 | } 344 | 345 | /* Literal.Number.Oct */ 346 | .highlight .sa { 347 | color: #4e9a06 348 | } 349 | 350 | /* Literal.String.Affix */ 351 | .highlight .sb { 352 | color: #4e9a06 353 | } 354 | 355 | /* Literal.String.Backtick */ 356 | .highlight .sc { 357 | color: #4e9a06 358 | } 359 | 360 | /* Literal.String.Char */ 361 | .highlight .dl { 362 | color: #4e9a06 363 | } 364 | 365 | /* Literal.String.Delimiter */ 366 | .highlight .sd { 367 | color: #8f5902; 368 | font-style: italic 369 | } 370 | 371 | /* Literal.String.Doc */ 372 | .highlight .s2 { 373 | color: #4e9a06 374 | } 375 | 376 | /* Literal.String.Double */ 377 | .highlight .se { 378 | color: #4e9a06 379 | } 380 | 381 | /* Literal.String.Escape */ 382 | .highlight .sh { 383 | color: #4e9a06 384 | } 385 | 386 | /* Literal.String.Heredoc */ 387 | .highlight .si { 388 | color: #4e9a06 389 | } 390 | 391 | /* Literal.String.Interpol */ 392 | .highlight .sx { 393 | color: #4e9a06 394 | } 395 | 396 | /* Literal.String.Other */ 397 | .highlight .sr { 398 | color: #4e9a06 399 | } 400 | 401 | /* Literal.String.Regex */ 402 | .highlight .s1 { 403 | color: #4e9a06 404 | } 405 | 406 | /* Literal.String.Single */ 407 | .highlight .ss { 408 | color: #4e9a06 409 | } 410 | 411 | /* Literal.String.Symbol */ 412 | .highlight .bp { 413 | color: #3465a4 414 | } 415 | 416 | /* Name.Builtin.Pseudo */ 417 | .highlight .fm { 418 | color: #000000 419 | } 420 | 421 | /* Name.Function.Magic */ 422 | .highlight .vc { 423 | color: #000000 424 | } 425 | 426 | /* Name.Variable.Class */ 427 | .highlight .vg { 428 | color: #000000 429 | } 430 | 431 | /* Name.Variable.Global */ 432 | .highlight .vi { 433 | color: #000000 434 | } 435 | 436 | /* Name.Variable.Instance */ 437 | .highlight .vm { 438 | color: #000000 439 | } 440 | 441 | /* Name.Variable.Magic */ 442 | .highlight .il { 443 | color: #990000 444 | } 445 | 446 | /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/sphinx_highlight.js: -------------------------------------------------------------------------------- 1 | /* Highlighting utilities for Sphinx HTML documentation. */ 2 | "use strict"; 3 | 4 | const SPHINX_HIGHLIGHT_ENABLED = true 5 | 6 | /** 7 | * highlight a given string on a node by wrapping it in 8 | * span elements with the given class name. 9 | */ 10 | const _highlight = (node, addItems, text, className) => { 11 | if (node.nodeType === Node.TEXT_NODE) { 12 | const val = node.nodeValue; 13 | const parent = node.parentNode; 14 | const pos = val.toLowerCase().indexOf(text); 15 | if ( 16 | pos >= 0 && 17 | !parent.classList.contains(className) && 18 | !parent.classList.contains("nohighlight") 19 | ) { 20 | let span; 21 | 22 | const closestNode = parent.closest("body, svg, foreignObject"); 23 | const isInSVG = closestNode && closestNode.matches("svg"); 24 | if (isInSVG) { 25 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); 26 | } else { 27 | span = document.createElement("span"); 28 | span.classList.add(className); 29 | } 30 | 31 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 32 | parent.insertBefore( 33 | span, 34 | parent.insertBefore( 35 | document.createTextNode(val.substr(pos + text.length)), 36 | node.nextSibling 37 | ) 38 | ); 39 | node.nodeValue = val.substr(0, pos); 40 | 41 | if (isInSVG) { 42 | const rect = document.createElementNS( 43 | "http://www.w3.org/2000/svg", 44 | "rect" 45 | ); 46 | const bbox = parent.getBBox(); 47 | rect.x.baseVal.value = bbox.x; 48 | rect.y.baseVal.value = bbox.y; 49 | rect.width.baseVal.value = bbox.width; 50 | rect.height.baseVal.value = bbox.height; 51 | rect.setAttribute("class", className); 52 | addItems.push({parent: parent, target: rect}); 53 | } 54 | } 55 | } else if (node.matches && !node.matches("button, select, textarea")) { 56 | node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); 57 | } 58 | }; 59 | const _highlightText = (thisNode, text, className) => { 60 | let addItems = []; 61 | _highlight(thisNode, addItems, text, className); 62 | addItems.forEach((obj) => 63 | obj.parent.insertAdjacentElement("beforebegin", obj.target) 64 | ); 65 | }; 66 | 67 | /** 68 | * Small JavaScript module for the documentation. 69 | */ 70 | const SphinxHighlight = { 71 | 72 | /** 73 | * highlight the search words provided in localstorage in the text 74 | */ 75 | highlightSearchWords: () => { 76 | if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight 77 | 78 | // get and clear terms from localstorage 79 | const url = new URL(window.location); 80 | const highlight = 81 | localStorage.getItem("sphinx_highlight_terms") 82 | || url.searchParams.get("highlight") 83 | || ""; 84 | localStorage.removeItem("sphinx_highlight_terms") 85 | url.searchParams.delete("highlight"); 86 | window.history.replaceState({}, "", url); 87 | 88 | // get individual terms from highlight string 89 | const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); 90 | if (terms.length === 0) return; // nothing to do 91 | 92 | // There should never be more than one element matching "div.body" 93 | const divBody = document.querySelectorAll("div.body"); 94 | const body = divBody.length ? divBody[0] : document.querySelector("body"); 95 | window.setTimeout(() => { 96 | terms.forEach((term) => _highlightText(body, term, "highlighted")); 97 | }, 10); 98 | 99 | const searchBox = document.getElementById("searchbox"); 100 | if (searchBox === null) return; 101 | searchBox.appendChild( 102 | document 103 | .createRange() 104 | .createContextualFragment( 105 | '" 109 | ) 110 | ); 111 | }, 112 | 113 | /** 114 | * helper function to hide the search marks again 115 | */ 116 | hideSearchWords: () => { 117 | document 118 | .querySelectorAll("#searchbox .highlight-link") 119 | .forEach((el) => el.remove()); 120 | document 121 | .querySelectorAll("span.highlighted") 122 | .forEach((el) => el.classList.remove("highlighted")); 123 | localStorage.removeItem("sphinx_highlight_terms") 124 | }, 125 | 126 | initEscapeListener: () => { 127 | // only install a listener if it is really needed 128 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; 129 | 130 | document.addEventListener("keydown", (event) => { 131 | // bail for input elements 132 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 133 | // bail with special keys 134 | if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; 135 | if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { 136 | SphinxHighlight.hideSearchWords(); 137 | event.preventDefault(); 138 | } 139 | }); 140 | }, 141 | }; 142 | 143 | _ready(SphinxHighlight.highlightSearchWords); 144 | _ready(SphinxHighlight.initEscapeListener); 145 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/_static/underscore.js: -------------------------------------------------------------------------------- 1 | !function(n,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define("underscore",r):(n="undefined"!=typeof globalThis?globalThis:n||self,function(){var t=n._,e=n._=r();e.noConflict=function(){return n._=t,e}}())}(this,(function(){ 2 | // Underscore.js 1.13.1 3 | // https://underscorejs.org 4 | // (c) 2009-2021 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors 5 | // Underscore may be freely distributed under the MIT license. 6 | var n="1.13.1",r="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||Function("return this")()||{},t=Array.prototype,e=Object.prototype,u="undefined"!=typeof Symbol?Symbol.prototype:null,o=t.push,i=t.slice,a=e.toString,f=e.hasOwnProperty,c="undefined"!=typeof ArrayBuffer,l="undefined"!=typeof DataView,s=Array.isArray,p=Object.keys,v=Object.create,h=c&&ArrayBuffer.isView,y=isNaN,d=isFinite,g=!{toString:null}.propertyIsEnumerable("toString"),b=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],m=Math.pow(2,53)-1;function j(n,r){return r=null==r?n.length-1:+r,function(){for(var t=Math.max(arguments.length-r,0),e=Array(t),u=0;u=0&&t<=m}}function J(n){return function(r){return null==r?void 0:r[n]}}var G=J("byteLength"),H=K(G),Q=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var X=c?function(n){return h?h(n)&&!q(n):H(n)&&Q.test(a.call(n))}:C(!1),Y=J("length");function Z(n,r){r=function(n){for(var r={},t=n.length,e=0;e":">",'"':""","'":"'","`":"`"},Cn=Ln($n),Kn=Ln(_n($n)),Jn=tn.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},Gn=/(.)^/,Hn={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},Qn=/\\|'|\r|\n|\u2028|\u2029/g;function Xn(n){return"\\"+Hn[n]}var Yn=/^\s*(\w|\$)+\s*$/;var Zn=0;function nr(n,r,t,e,u){if(!(e instanceof r))return n.apply(t,u);var o=Mn(n.prototype),i=n.apply(o,u);return _(i)?i:o}var rr=j((function(n,r){var t=rr.placeholder,e=function(){for(var u=0,o=r.length,i=Array(o),a=0;a1)ur(a,r-1,t,e),u=e.length;else for(var f=0,c=a.length;f0&&(t=r.apply(this,arguments)),n<=1&&(r=null),t}}var lr=rr(cr,2);function sr(n,r,t){r=qn(r,t);for(var e,u=nn(n),o=0,i=u.length;o0?0:u-1;o>=0&&o0?a=o>=0?o:Math.max(o+f,a):f=o>=0?Math.min(o+1,f):o+f+1;else if(t&&o&&f)return e[o=t(e,u)]===u?o:-1;if(u!=u)return(o=r(i.call(e,a,f),$))>=0?o+a:-1;for(o=n>0?a:f-1;o>=0&&o0?0:i-1;for(u||(e=r[o?o[a]:a],a+=n);a>=0&&a=3;return r(n,Fn(t,u,4),e,o)}}var Ar=wr(1),xr=wr(-1);function Sr(n,r,t){var e=[];return r=qn(r,t),jr(n,(function(n,t,u){r(n,t,u)&&e.push(n)})),e}function Or(n,r,t){r=qn(r,t);for(var e=!er(n)&&nn(n),u=(e||n).length,o=0;o=0}var Br=j((function(n,r,t){var e,u;return D(r)?u=r:(r=Nn(r),e=r.slice(0,-1),r=r[r.length-1]),_r(n,(function(n){var o=u;if(!o){if(e&&e.length&&(n=In(n,e)),null==n)return;o=n[r]}return null==o?o:o.apply(n,t)}))}));function Nr(n,r){return _r(n,Rn(r))}function Ir(n,r,t){var e,u,o=-1/0,i=-1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=er(n)?n:jn(n)).length;ao&&(o=e);else r=qn(r,t),jr(n,(function(n,t,e){((u=r(n,t,e))>i||u===-1/0&&o===-1/0)&&(o=n,i=u)}));return o}function Tr(n,r,t){if(null==r||t)return er(n)||(n=jn(n)),n[Wn(n.length-1)];var e=er(n)?En(n):jn(n),u=Y(e);r=Math.max(Math.min(r,u),0);for(var o=u-1,i=0;i1&&(e=Fn(e,r[1])),r=an(n)):(e=qr,r=ur(r,!1,!1),n=Object(n));for(var u=0,o=r.length;u1&&(t=r[1])):(r=_r(ur(r,!1,!1),String),e=function(n,t){return!Er(r,t)}),Ur(n,e,t)}));function zr(n,r,t){return i.call(n,0,Math.max(0,n.length-(null==r||t?1:r)))}function Lr(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null==r||t?n[0]:zr(n,n.length-r)}function $r(n,r,t){return i.call(n,null==r||t?1:r)}var Cr=j((function(n,r){return r=ur(r,!0,!0),Sr(n,(function(n){return!Er(r,n)}))})),Kr=j((function(n,r){return Cr(n,r)}));function Jr(n,r,t,e){A(r)||(e=t,t=r,r=!1),null!=t&&(t=qn(t,e));for(var u=[],o=[],i=0,a=Y(n);ir?(e&&(clearTimeout(e),e=null),a=c,i=n.apply(u,o),e||(u=o=null)):e||!1===t.trailing||(e=setTimeout(f,l)),i};return c.cancel=function(){clearTimeout(e),a=0,e=u=o=null},c},debounce:function(n,r,t){var e,u,o,i,a,f=function(){var c=zn()-u;r>c?e=setTimeout(f,r-c):(e=null,t||(i=n.apply(a,o)),e||(o=a=null))},c=j((function(c){return a=this,o=c,u=zn(),e||(e=setTimeout(f,r),t&&(i=n.apply(a,o))),i}));return c.cancel=function(){clearTimeout(e),e=o=a=null},c},wrap:function(n,r){return rr(r,n)},negate:fr,compose:function(){var n=arguments,r=n.length-1;return function(){for(var t=r,e=n[r].apply(this,arguments);t--;)e=n[t].call(this,e);return e}},after:function(n,r){return function(){if(--n<1)return r.apply(this,arguments)}},before:cr,once:lr,findKey:sr,findIndex:vr,findLastIndex:hr,sortedIndex:yr,indexOf:gr,lastIndexOf:br,find:mr,detect:mr,findWhere:function(n,r){return mr(n,Dn(r))},each:jr,forEach:jr,map:_r,collect:_r,reduce:Ar,foldl:Ar,inject:Ar,reduceRight:xr,foldr:xr,filter:Sr,select:Sr,reject:function(n,r,t){return Sr(n,fr(qn(r)),t)},every:Or,all:Or,some:Mr,any:Mr,contains:Er,includes:Er,include:Er,invoke:Br,pluck:Nr,where:function(n,r){return Sr(n,Dn(r))},max:Ir,min:function(n,r,t){var e,u,o=1/0,i=1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=er(n)?n:jn(n)).length;ae||void 0===t)return 1;if(t 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | bitmart package — hftcryptoapi 0.0.1 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 | 34 | 35 |
36 | 37 |
38 |

bitmart package

40 |
41 |

Submodules 42 |

43 |
44 |
45 |

bitmart.Bitmart module

47 |
48 |
49 |

bitmart.api_client module

51 |
52 |
53 |

bitmart.bitmart_errors module

55 |
56 |
57 |

bitmart.bitmart_exceptions module

60 |
61 |
62 |

bitmart.bitmart_objects module

64 |
65 |
66 |

bitmart.bitmart_utils module

68 |
69 |
70 |

bitmart.bitmart_websockets module

73 |
74 |
75 |

bitmart.bm_logging module

77 |
78 |
79 |

bitmart.client_keys module

81 |
82 |
83 |

bitmart.constants module

85 |
86 |
87 |

Module contents

89 |
90 |
91 | 92 | 93 |
94 | 95 |
96 |
97 | 128 |
129 |
130 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/genindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Index — hftcryptoapi 0.0.1 documentation 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 |
31 | 32 | 33 |
34 | 35 | 36 |

Index

37 | 38 |
39 | 40 |
41 | 42 | 43 |
44 | 45 |
46 |
47 | 78 |
79 |
80 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Welcome to hftcryptoapi’s documentation! — hftcryptoapi 0.0.1 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 | 34 | 35 |
36 | 37 |
38 |

Welcome to hftcryptoapi’s documentation!

41 |
42 |
43 |
44 |
45 |

Indices and tables

47 | 55 |
56 | 57 | 58 |
59 | 60 |
61 |
62 | 93 |
94 |
95 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/modules.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | bitmart — hftcryptoapi 0.0.1 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | 89 | 120 |
121 |
122 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/hftcryptoapi/bitmart/docs/build/html/objects.inv -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Search — hftcryptoapi 0.0.1 documentation 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 | 38 | 39 |
40 | 41 |

Search

42 | 43 | 51 | 52 | 53 |

54 | Searching for multiple words only shows matches that contain 55 | all words. 56 |

57 | 58 | 59 |
60 | 62 | 63 | 64 |
65 | 66 | 67 |
68 | 69 |
70 | 71 | 72 |
73 | 74 |
75 |
76 | 96 |
97 |
98 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/build/html/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({ 2 | "docnames": ["bitmart", "index", "modules"], 3 | "filenames": ["bitmart.rst", "index.rst", "modules.rst"], 4 | "titles": ["bitmart package", "Welcome to hftcryptoapi\u2019s documentation!", "bitmart"], 5 | "terms": { 6 | "index": 1, 7 | "modul": [1, 2], 8 | "search": 1, 9 | "page": 1, 10 | "packag": 2, 11 | "submodul": 2, 12 | "api_cli": 2, 13 | "bitmart_error": 2, 14 | "bitmart_except": 2, 15 | "bitmart_object": 2, 16 | "bitmart_util": 2, 17 | "bitmart_websocket": 2, 18 | "bm_log": 2, 19 | "client_kei": 2, 20 | "constant": 2, 21 | "content": 2 22 | }, 23 | "objects": {}, 24 | "objtypes": {}, 25 | "objnames": {}, 26 | "titleterms": { 27 | "bitmart": [0, 2], 28 | "packag": 0, 29 | "submodul": 0, 30 | "modul": 0, 31 | "api_cli": 0, 32 | "bitmart_error": 0, 33 | "bitmart_except": 0, 34 | "bitmart_object": 0, 35 | "bitmart_util": 0, 36 | "bitmart_websocket": 0, 37 | "bm_log": 0, 38 | "client_kei": 0, 39 | "constant": 0, 40 | "content": 0, 41 | "welcom": 1, 42 | "hftcryptoapi": 1, 43 | "": 1, 44 | "document": 1, 45 | "indic": 1, 46 | "tabl": 1 47 | }, 48 | "envversion": { 49 | "sphinx.domains.c": 2, 50 | "sphinx.domains.changeset": 1, 51 | "sphinx.domains.citation": 1, 52 | "sphinx.domains.cpp": 8, 53 | "sphinx.domains.index": 1, 54 | "sphinx.domains.javascript": 2, 55 | "sphinx.domains.math": 2, 56 | "sphinx.domains.python": 3, 57 | "sphinx.domains.rst": 2, 58 | "sphinx.domains.std": 2, 59 | "sphinx": 57 60 | }, 61 | "alltitles": { 62 | "bitmart package": [[0, "bitmart-package"]], 63 | "Submodules": [[0, "submodules"]], 64 | "bitmart.Bitmart module": [[0, "bitmart-bitmart-module"]], 65 | "bitmart.api_client module": [[0, "bitmart-api-client-module"]], 66 | "bitmart.bitmart_errors module": [[0, "bitmart-bitmart-errors-module"]], 67 | "bitmart.bitmart_exceptions module": [[0, "bitmart-bitmart-exceptions-module"]], 68 | "bitmart.bitmart_objects module": [[0, "bitmart-bitmart-objects-module"]], 69 | "bitmart.bitmart_utils module": [[0, "bitmart-bitmart-utils-module"]], 70 | "bitmart.bitmart_websockets module": [[0, "bitmart-bitmart-websockets-module"]], 71 | "bitmart.bm_logging module": [[0, "bitmart-bm-logging-module"]], 72 | "bitmart.client_keys module": [[0, "bitmart-client-keys-module"]], 73 | "bitmart.constants module": [[0, "bitmart-constants-module"]], 74 | "Module contents": [[0, "module-contents"]], 75 | "Welcome to hftcryptoapi\u2019s documentation!": [[1, "welcome-to-hftcryptoapi-s-documentation"]], 76 | "Indices and tables": [[1, "indices-and-tables"]], 77 | "bitmart": [[2, "bitmart"]] 78 | }, 79 | "indexentries": {} 80 | }) -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/source/bitmart.rst: -------------------------------------------------------------------------------- 1 | bitmart package 2 | =============== 3 | 4 | Submodules 5 | ---------- 6 | 7 | bitmart.Bitmart module 8 | ---------------------- 9 | 10 | .. automodule:: bitmart.Bitmart 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | bitmart.api\_client module 16 | -------------------------- 17 | 18 | .. automodule:: bitmart.api_client 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | bitmart.bitmart\_errors module 24 | ------------------------------ 25 | 26 | .. automodule:: bitmart.bitmart_errors 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | bitmart.bitmart\_exceptions module 32 | ---------------------------------- 33 | 34 | .. automodule:: bitmart.bitmart_exceptions 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | bitmart.bitmart\_objects module 40 | ------------------------------- 41 | 42 | .. automodule:: bitmart.bitmart_objects 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | bitmart.bitmart\_utils module 48 | ----------------------------- 49 | 50 | .. automodule:: bitmart.bitmart_utils 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | bitmart.bitmart\_websockets module 56 | ---------------------------------- 57 | 58 | .. automodule:: bitmart.bitmart_websockets 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | 63 | bitmart.bm\_logging module 64 | -------------------------- 65 | 66 | .. automodule:: bitmart.bm_logging 67 | :members: 68 | :undoc-members: 69 | :show-inheritance: 70 | 71 | bitmart.client\_keys module 72 | --------------------------- 73 | 74 | .. automodule:: bitmart.client_keys 75 | :members: 76 | :undoc-members: 77 | :show-inheritance: 78 | 79 | bitmart.constants module 80 | ------------------------ 81 | 82 | .. automodule:: bitmart.constants 83 | :members: 84 | :undoc-members: 85 | :show-inheritance: 86 | 87 | Module contents 88 | --------------- 89 | 90 | .. automodule:: bitmart 91 | :members: 92 | :undoc-members: 93 | :show-inheritance: 94 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | # -- Project information ----------------------------------------------------- 7 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 8 | import os 9 | import sys 10 | 11 | sys.path.insert(0, os.path.abspath("../../")) 12 | 13 | project = "hftcryptoapi" 14 | copyright = "2022, Ruslan Lazarev" 15 | author = "Ruslan Lazarev" 16 | release = "0.0.1" 17 | 18 | # -- General configuration --------------------------------------------------- 19 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 20 | 21 | extensions = ["sphinx.ext.todo", "sphinx.ext.viewcode", "såhinx.ext.autodoc"] 22 | autosummary_generate = True 23 | templates_path = ["_templates"] 24 | exclude_patterns = [] 25 | 26 | # -- Options for HTML output ------------------------------------------------- 27 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 28 | 29 | html_theme = "alabaster" 30 | html_static_path = ["_static"] 31 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. hftcryptoapi documentation master file, created by 2 | sphinx-quickstart on Mon Dec 5 23:14:33 2022. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to hftcryptoapi's documentation! 7 | ======================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/docs/source/modules.rst: -------------------------------------------------------------------------------- 1 | bitmart 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | bitmart 8 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/exceptions.py: -------------------------------------------------------------------------------- 1 | class APIException(Exception): 2 | 3 | def __init__(self, response): 4 | self.status_code = response.status_code 5 | self.response = response.text 6 | self.url = response.url 7 | 8 | def __str__(self): 9 | return "APIException(http status=%s): response=%s url=%s" % ( 10 | self.status_code, 11 | self.response, 12 | self.url, 13 | ) 14 | 15 | 16 | class WebSocketException(Exception): 17 | def __init__(self, error_response): 18 | self.message = error_response.get("errorMessage", "") 19 | self.code = error_response.get("errorCode", "") 20 | self.error_response = error_response 21 | 22 | def __str__(self): 23 | return "WebSocketException: message=%s code=%s" % (self.message, self.code) 24 | 25 | 26 | class AuthException(Exception): 27 | pass 28 | 29 | 30 | class RequestException(Exception): 31 | 32 | def __init__(self, message): 33 | self.message = message 34 | 35 | def __str__(self): 36 | return "RequestException: %s" % self.message 37 | 38 | 39 | class ParamsException(Exception): 40 | 41 | def __init__(self, message): 42 | self.message = message 43 | 44 | def __str__(self): 45 | return "ParamsException: %s" % self.message 46 | -------------------------------------------------------------------------------- /hftcryptoapi/bitmart/ws_base.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | import threading 4 | 5 | import websockets 6 | 7 | from hftcryptoapi.bitmart.data import * 8 | from .bitmart_utils import sign, get_timestamp, get_kline_time 9 | 10 | 11 | # logging.getLogger().setLevel(logging.INFO) 12 | 13 | 14 | class BitmartWs(object): 15 | def __init__( 16 | self, uri: str, market: Market, api_key=None, memo=None, secret_key=None 17 | ): 18 | self.uri = uri 19 | self.ws: websockets.WebSocketClientProtocol = None 20 | self.loop = asyncio.new_event_loop() 21 | self.is_connected = False 22 | self.market = market 23 | self.api_key = api_key 24 | self.memo = memo 25 | self.secret_key = secret_key 26 | self.ws_thread = threading.Thread(target=self._run_sync, args=()) 27 | self.params = [] 28 | self.on_message = None 29 | self.is_stop = False 30 | self.name_of_group = "group" if market == market.FUTURES else "table" 31 | 32 | def _get_subscription_list( 33 | self, channels: List[str], symbols: Optional[List[str]] = None 34 | ): 35 | params = [] 36 | if symbols is None: 37 | params += channels 38 | else: 39 | for c in channels: 40 | for s in symbols: 41 | params.append(f"{c}:{s}") 42 | return params 43 | 44 | def _mange_socket_subscriptions( 45 | self, 46 | channels: List[str], 47 | symbols: Optional[List[str]] = None, 48 | subscribe: bool = True, 49 | ): 50 | params = self._get_subscription_list(channels, symbols) 51 | self.params += params 52 | if self.is_connected: 53 | if subscribe: 54 | asyncio.run(self._subscribe(params)) 55 | else: 56 | asyncio.run(self._unsubscribe(params)) 57 | 58 | def subscribe(self, channels: List[str], symbols: Optional[List[str]] = None): 59 | self._mange_socket_subscriptions(channels, symbols, True) 60 | 61 | def unsubscribe(self, channels: List[str], symbols: Optional[List[str]] = None): 62 | self._mange_socket_subscriptions(channels, symbols, False) 63 | 64 | def _run_sync(self): 65 | asyncio.run(self._socket_loop()) 66 | 67 | def start(self, on_message=None): 68 | self.on_message = on_message 69 | if len(self.params) > 0: 70 | self.ws_thread.start() 71 | return True 72 | self.is_stop = False 73 | return False 74 | 75 | def stop(self): 76 | self.is_stop = True 77 | try: 78 | if self.is_connected: 79 | pass 80 | # self.loop.call_soon_threadsafe(self.loop.stop) 81 | try: 82 | self.loop.run_until_complete(self.ws.close()) 83 | self.loop.stop() 84 | except ValueError: 85 | pass 86 | self.ws_thread.join() 87 | except RuntimeError: 88 | pass 89 | 90 | def _on_message(self, message): 91 | try: 92 | if message.get("errorMessage"): 93 | raise WebSocketException(message) 94 | if message.get("action", False): 95 | logging.debug(message) 96 | else: 97 | group = message[self.name_of_group] 98 | data = message["data"] 99 | if "/ticker" in group: 100 | is_futures = self.market == Market.FUTURES 101 | if is_futures: 102 | self.on_message(TickerFuturesWebSocket(**data)) 103 | else: 104 | for item in data: 105 | ticker = TickerSpotWebSocket(**item) 106 | self.on_message(ticker) 107 | elif "spot/kline" in group: 108 | for item in data: 109 | kline = WebSocketKline( 110 | symbol=item["symbol"], 111 | candle=list(item["candle"]), 112 | market=self.market, 113 | ) 114 | self.on_message(kline) 115 | elif "futures/kline" in group: 116 | items = data["items"] 117 | for item in items: 118 | kline = WebSocketKline( 119 | symbol=data["symbol"], 120 | candle=list(item.values()), 121 | market=self.market, 122 | ) 123 | if self.market == Market.FUTURES: 124 | kline.date_time = get_kline_time( 125 | BtFuturesSocketKlineChannels(group.split(":")[0]) 126 | ) 127 | self.on_message(kline) 128 | elif "/position" in group: 129 | for item in data: 130 | self.on_message(WebSocketPositionFutures(**item)) 131 | elif "/asset" in group: 132 | self.on_message(WebSocketAssetFutures(**data)) 133 | elif "spot/depth" in group: 134 | for item in data: 135 | self.on_message(WebSocketDepthSpot(**item)) 136 | elif "futures/depth" in group: 137 | self.on_message(WebSocketDepthFutures(**data)) 138 | elif "spot/trade" in group: 139 | for item in data: 140 | self.on_message(WebSocketTrade(**item)) 141 | elif "spot/order" in group: 142 | for item in data: 143 | self.on_message(WebSocketOrderProgress(**item)) 144 | except WebSocketException as e: 145 | raise e 146 | except Exception as e: 147 | logging.error(f"WS on message: {e}") 148 | 149 | async def _connect(self): 150 | while True: 151 | try: 152 | if self.is_connected: 153 | logging.warning(f"WS {self.market} Closing") 154 | await self.ws.close() 155 | logging.info(f"WS {self.market} Connecting") 156 | self.ws = await websockets.connect( 157 | self.uri, ping_interval=10, ping_timeout=10 158 | ) 159 | self.is_connected = True 160 | logging.info(f"WS {self.market} Connected") 161 | break 162 | except TimeoutError: 163 | logging.error(f"WS {self.market} timeout.") 164 | except Exception as ex: 165 | logging.error(f"WS {self.market} exception: {ex}") 166 | await asyncio.sleep(1) 167 | 168 | async def _read_socket(self): 169 | try: 170 | while not self.is_stop: 171 | message = await self.ws.recv() 172 | try: 173 | for line in str(message).splitlines(): 174 | self._on_message(json.loads(line)) # await 175 | except Exception as e: 176 | logging.info(f"WS read error {e}") 177 | except websockets.ConnectionClosedError as e: 178 | sleep_time = 3 179 | logging.warning( 180 | f"WS {self.market} Connection Error: {e}. Sleep {sleep_time}..." 181 | ) 182 | await asyncio.sleep(sleep_time) 183 | except Exception as e: 184 | if not self.is_stop: 185 | logging.warning( 186 | f"WS {self.market} Connection Lost at {datetime.utcnow()} {e}" 187 | ) 188 | 189 | async def _auth(self): 190 | if self.api_key is not None: 191 | timestamp = get_timestamp() 192 | sign_ = sign(f"{timestamp}#{self.memo}#bitmart.WebSocket", self.secret_key) 193 | params = {"args": [self.api_key, timestamp, sign_]} 194 | if self.market is Market.FUTURES: 195 | params["action"] = "access" 196 | params["args"].append("web") 197 | else: 198 | params["op"] = "login" 199 | auth_str = json.dumps(params) 200 | await self.ws.send(auth_str) 201 | message = await self.ws.recv() 202 | 203 | async def _subscribe(self, params): 204 | action_name = "action" if self.market == Market.FUTURES else "op" 205 | await self.ws.send(json.dumps({action_name: "subscribe", "args": params})) 206 | 207 | async def _unsubscribe(self, params): 208 | action_name = "action" if self.market == Market.FUTURES else "op" 209 | await self.ws.send(json.dumps({action_name: "unsubscribe", "args": params})) 210 | 211 | async def _socket_loop(self): 212 | asyncio.set_event_loop(self.loop) 213 | while not self.is_stop: 214 | await self._connect() 215 | await self._auth() 216 | await self._subscribe(self.params) 217 | await self._read_socket() 218 | self.is_connected = False 219 | # await self.ws.close() 220 | -------------------------------------------------------------------------------- /hftcryptoapi/data/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.0.1" 2 | -------------------------------------------------------------------------------- /hftcryptoapi/data/historical/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.0.1" 2 | -------------------------------------------------------------------------------- /hftcryptoapi/data/historical/utils.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from typing import Type, Dict 3 | 4 | from hftcryptoapi.common.common_types import HTTPResult, RawData 5 | 6 | """ 7 | These functions were created and put in this file to handle all of the edge cases 8 | for parsing data that exist in the market data API. 9 | 10 | v2/stocks and v1beta2/crypto 11 | """ 12 | 13 | 14 | def parse_obj_as_symbol_dict(model: Type, raw_data: RawData) -> Dict[str, Type]: 15 | """ 16 | Parses raw_data into a dictionary where the keys are the string valued symbols and the values are the 17 | parsed data into the model. 18 | 19 | Args: 20 | model (Type): The model we want to parse the data into 21 | raw_data (RawData): The raw data from the API 22 | 23 | Returns: 24 | Dict[str, Type]: The symbol keyed dictionary of parsed data 25 | """ 26 | return {k: model(symbol=k, raw_data=v) for k, v in raw_data.items()} 27 | 28 | 29 | def get_data_from_response(response: HTTPResult) -> RawData: 30 | """ 31 | From the raw API response, retrieves the field that contains market data. 32 | 33 | Args: 34 | response (HTTPResult): The raw API response 35 | 36 | Returns: 37 | RawData: The market data from the response 38 | """ 39 | data_keys = { 40 | "trade", 41 | "trades", 42 | "quote", 43 | "quotes", 44 | "bar", 45 | "bars", 46 | "snapshot", 47 | "snapshots", 48 | "orderbook", 49 | "orderbooks", 50 | } 51 | 52 | selected_key = data_keys.intersection(response) 53 | 54 | if selected_key is None or len(selected_key) < 1: 55 | raise ValueError("The data in response does not match any known keys.") 56 | 57 | # assume selected_key only contains 1 value 58 | selected_key = selected_key.pop() 59 | 60 | # formatting a single symbol response so that this method 61 | # always returns a symbol keyed data dictionary 62 | if "symbol" in response: 63 | return {response["symbol"]: response[selected_key]} 64 | 65 | return response[selected_key] 66 | 67 | 68 | def format_dataset_response( 69 | response: HTTPResult, data_by_symbol: defaultdict 70 | ) -> defaultdict: 71 | """ 72 | Formats data from BarSet, TradeSet endpoints. Uses defaultdict for simpler syntax when 73 | doing list comprehension. 74 | 75 | Args: 76 | response (HTTPResult): The raw response from bars, trades, quotes, endpoint 77 | data_by_symbol (defaultdict): The dictionary we want to format the raw response into 78 | 79 | Returns: 80 | defaultdict: The dictionary populated with data 81 | """ 82 | # data_by_symbol is in format of 83 | # { 84 | # "symbol1": [ "data1", "data2", ... ], 85 | # "symbol2": [ "data1", "data2", ... ], 86 | # .... 87 | # } 88 | 89 | response_data = get_data_from_response(response) 90 | 91 | # add elements to data_by_symbol 92 | # for list data data just extend 93 | # for non-list data, add as element of a list. 94 | # list comprehension used for speed 95 | [ 96 | data_by_symbol[symbol].extend(data) 97 | if isinstance(data, list) 98 | else data_by_symbol[symbol].append(data) 99 | for symbol, data in response_data.items() 100 | ] 101 | 102 | return data_by_symbol 103 | 104 | 105 | def format_latest_data_response( 106 | response: HTTPResult, data_by_symbol: defaultdict 107 | ) -> defaultdict: 108 | """ 109 | Parses data from the "latest" endpoints and populates the data_by_symbol dict. (latest_quote, latest_bar). Also includes crypto/snapshots endpoint, 110 | but not stocks/snapshots. 111 | 112 | Args: 113 | response (HTTPResult): The response from the latest data endpoint. 114 | data_by_symbol (defaultdict): The dictionary we want to format the raw response into 115 | 116 | Returns: 117 | defaultdict: The dictionary populated with latest data points 118 | """ 119 | response_data = get_data_from_response(response) 120 | 121 | for symbol, data in response_data.items(): 122 | data_by_symbol[symbol] = data 123 | 124 | return data_by_symbol 125 | 126 | 127 | def format_snapshot_data( 128 | response: HTTPResult, data_by_symbol: defaultdict 129 | ) -> defaultdict: 130 | """ 131 | Formats data from stocks/snapshot endpoint. Exists because v2/stocks/snapshot 132 | is different from v1beta2/crypto/snapshot. 133 | 134 | Args: 135 | response (HTTPResult): The raw response from v2/stocks/snapshot endpoint 136 | data_by_symbol (defaultdict): The dictionary we want to format the raw response into 137 | 138 | Returns: 139 | defaultdict: The dictionary populated with data 140 | """ 141 | # TODO: Improve snapshot parsing. 142 | if "symbol" in response: 143 | symbol = response["symbol"] 144 | del response["symbol"] 145 | data_by_symbol[symbol] = response 146 | else: 147 | for symbol, data in response.items(): 148 | data_by_symbol[symbol] = data 149 | 150 | return data_by_symbol 151 | -------------------------------------------------------------------------------- /hftcryptoapi/data/live/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.0.1" 2 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["hatchling"] 3 | build-backend = "hatchling.build" 4 | [project] 5 | name = "HFT-Crypto-API" 6 | version = "1.0.6" 7 | description = "Bitmarket REST/Websocket Api implementation" 8 | readme = "README.md" 9 | authors = [{ name = "HFT-Crypto-API", email = "acidpictures@gmail.com" }] 10 | license = { file = "LICENSE" } 11 | classifiers = ["Programming Language :: Python :: 3"] 12 | dependencies = [ 13 | "requests==2.31.0", 14 | "urllib3==1.26.18", 15 | "utils==1.0.1", 16 | "websockets>=9.1", 17 | "pytest==6.2.1", 18 | "pydantic==1.10.2" 19 | ] 20 | [project.urls] 21 | Homepage = "https://github.com/hftcryptobot/HFT-Crypto-API" 22 | 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests>=2.25 2 | urllib3>=1.26 3 | utils==1.0.1 4 | websockets>=9.1 5 | pytest==6.2.1 6 | pydantic==1.10.2 7 | pandas~=2.2.2 8 | ta~=0.11.0 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hftcryptobot/HFT-Crypto-API/d74b222946ce967654cf3e2cc85a1228cf7e7398/setup.py -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------