From 52707d9acb5fd29450d4a018bb51399352211a91 Mon Sep 17 00:00:00 2001
From: dustoair <107600816+dustoair@users.noreply.github.com>
Date: Mon, 25 Jul 2022 19:22:24 +0800
Subject: [PATCH] open src
---
.drone.yml | 10 +
.gitignore | 118 +
Dockerfile | 7 +
Dockerfile-requirements | 5 +
README.md | 118 +
__init__.py | 0
bakreq.txt | 6 +
binance/__init__.py | 3 +
binance/binance_constant.py | 55 +
binance/binance_future.py | 345 ++
binance/binance_future_trader.py | 226 ++
binance/binance_spot.py | 456 +++
binance/binance_trader.py | 434 ++
binance/trade.txt | 12 +
binance/trader_bak | 404 ++
conf/config-example.json | 28 +
conf_huobi/config-example.json | 11 +
docker_build.md | 26 +
example/__init__.py | 0
.../account/get_account_asset_valuation.py | 24 +
example/account/get_account_balance.py | 3522 +++++++++++++++++
.../account/get_account_balance_by_subuid.py | 12 +
.../account/get_account_balance_sufficient.py | 33 +
example/account/get_account_by_type_symbol.py | 34 +
example/account/get_account_history.py | 11 +
example/account/get_account_ledger.py | 8 +
example/account/get_account_point.py | 8 +
example/account/get_accounts.py | 12 +
.../account/get_aggregated_subuser_balance.py | 10 +
example/account/get_balance.py | 9 +
example/account/post_account_transfer.py | 12 +
example/account/post_point_transfer.py | 8 +
example/account/post_sub_user_management.py | 13 +
.../post_transfer_between_futures_and_pro.py | 19 +
...ost_transfer_between_parent_and_subuser.py | 15 +
example/account/req_account_balance_list.py | 10 +
example/account/sub_account_update.py | 15 +
example/algo/get_open_orders.py | 10 +
example/algo/get_order.py | 10 +
example/algo/get_order_history.py | 10 +
example/algo/post_cancel_algo_orders.py | 17 +
example/algo/post_create_algo_order.py | 12 +
example/api_key.py | 3 +
example/etf/get_etf_swap_config.py | 16 +
example/etf/get_etf_swap_list.py | 24 +
example/etf/post_etf_swap_in.py | 23 +
example/etf/post_etf_swap_out.py | 22 +
example/generic/get_exchange_currencies.py | 9 +
example/generic/get_exchange_info.py | 13 +
example/generic/get_exchange_symbols.py | 13 +
example/generic/get_exchange_timestamp.py | 8 +
example/generic/get_market_status.py | 8 +
example/generic/get_reference_currencies.py | 13 +
example/generic/get_system_status.py | 12 +
.../get_cross_margin_account_balance.py | 9 +
example/margin/get_cross_margin_loan_info.py | 8 +
.../margin/get_cross_margin_loan_orders.py | 16 +
.../get_general_repayment_loan_records.py | 12 +
example/margin/get_margin_account_balance.py | 8 +
example/margin/get_margin_loan_info.py | 8 +
example/margin/get_margin_loan_orders.py | 8 +
.../post_cross_margin_create_loan_orders.py | 29 +
.../post_cross_margin_loan_order_repay.py | 19 +
example/margin/post_cross_margin_transfer.py | 12 +
example/margin/post_general_repay_loan.py | 8 +
example/margin/post_margin_create_order.py | 25 +
example/margin/post_margin_repay_order.py | 8 +
example/margin/post_margin_transfer_in.py | 8 +
example/margin/post_margin_transfer_out.py | 7 +
example/market/get_candlestick.py | 26 +
example/market/get_history_trade.py | 5 +
example/market/get_market_detail.py | 8 +
example/market/get_market_detail_merged.py | 9 +
example/market/get_market_tickers.py | 23 +
example/market/get_market_trade.py | 18 +
example/market/get_pricedepth.py | 21 +
example/market/req_candlestick.py | 16 +
example/market/req_market_detail.py | 12 +
example/market/req_mbp.py | 14 +
example/market/req_pricedepth.py | 15 +
example/market/req_trade_detail.py | 15 +
example/market/sub_candlestick.py | 18 +
example/market/sub_market_detail.py | 11 +
example/market/sub_mbp_full.py | 14 +
example/market/sub_mbp_increase.py | 14 +
example/market/sub_pricedepth.py | 18 +
example/market/sub_pricedepth_bbo.py | 15 +
example/market/sub_trade_detail.py | 13 +
example/subuser/get_uid.py | 10 +
example/subuser/get_user_apikey_info.py | 7 +
example/subuser/post_create_subuser.py | 17 +
.../post_set_subuser_transferability.py | 9 +
.../subuser/post_subuser_apikey_deletion.py | 10 +
.../subuser/post_subuser_apikey_generation.py | 13 +
.../post_subuser_apikey_modification.py | 12 +
example/subuser/post_trade_market.py | 12 +
example/trade/get_feerate.py | 10 +
.../trade/get_history_orders_in_48hours.py | 26 +
example/trade/get_matchresult.py | 11 +
example/trade/get_matchresult_by_order_id.py | 11 +
example/trade/get_open_orders.py | 25 +
example/trade/get_order.py | 10 +
example/trade/get_order_by_client_order_id.py | 12 +
example/trade/get_orders.py | 27 +
example/trade/get_transact_feerate.py | 9 +
example/trade/post_batch_cancel_open_order.py | 8 +
example/trade/post_batch_cancel_order.py | 21 +
example/trade/post_batch_create_order.py | 66 +
example/trade/post_cancel_client_order.py | 18 +
example/trade/post_cancel_order.py | 16 +
example/trade/post_client_order_id.py | 37 +
example/trade/post_create_order.py | 26 +
example/trade/post_transfer_futures_pro.py | 16 +
example/trade/req_order_detail.py | 14 +
example/trade/req_order_list.py | 22 +
example/trade/sub_order_update.py | 13 +
example/trade/sub_trade_clearing.py | 11 +
example/wallet/get_account_deposit_address.py | 16 +
.../wallet/get_account_withdraw_address.py | 14 +
example/wallet/get_account_withdraw_quota.py | 17 +
example/wallet/get_deposit_withdraw_list.py | 15 +
.../wallet/get_sub_user_deposit_address.py | 11 +
.../wallet/get_sub_user_deposit_history.py | 12 +
example/wallet/post_withdraw_and_cancel.py | 29 +
huobi/__init__.py | 1 +
huobi/client/__init__.py | 0
huobi/client/account.py | 374 ++
huobi/client/algo.py | 127 +
huobi/client/etf.py | 93 +
huobi/client/generic.py | 102 +
huobi/client/linear_swap.py | 540 +++
huobi/client/margin.py | 363 ++
huobi/client/market.py | 496 +++
huobi/client/subuser.py | 115 +
huobi/client/trade.py | 540 +++
huobi/client/wallet.py | 179 +
huobi/connection/__init__.py | 0
huobi/connection/impl/__init__.py | 1 +
huobi/connection/impl/private_def.py | 11 +
huobi/connection/impl/restapi_invoker.py | 94 +
huobi/connection/impl/restapi_request.py | 11 +
huobi/connection/impl/websocket_manage.py | 281 ++
huobi/connection/impl/websocket_request.py | 14 +
huobi/connection/impl/websocket_watchdog.py | 67 +
huobi/connection/restapi_sync_client.py | 154 +
huobi/connection/subscribe_client.py | 82 +
huobi/connection/websocket_req_client.py | 54 +
huobi/constant/__init__.py | 7 +
huobi/constant/definition.py | 366 ++
huobi/constant/result.py | 11 +
huobi/constant/system.py | 32 +
huobi/constant/test.py | 10 +
huobi/exception/__init__.py | 0
huobi/exception/huobi_api_exception.py | 14 +
huobi/model/__init__.py | 4 +
huobi/model/account/__init__.py | 14 +
huobi/model/account/account.py | 27 +
.../model/account/account_asset_valuation.py | 18 +
huobi/model/account/account_balance.py | 58 +
huobi/model/account/account_balance_req.py | 30 +
huobi/model/account/account_history.py | 36 +
huobi/model/account/account_ledger.py | 38 +
huobi/model/account/account_point_group.py | 25 +
huobi/model/account/account_point_result.py | 46 +
.../account/account_point_transfer_result.py | 20 +
.../model/account/account_transfer_result.py | 20 +
huobi/model/account/account_update.py | 35 +
huobi/model/account/account_update_event.py | 23 +
huobi/model/account/balance.py | 25 +
huobi/model/account/complete_subaccount.py | 27 +
huobi/model/account/margin_balance_detail.py | 24 +
huobi/model/account/sub_uid_management.py | 20 +
huobi/model/algo/__init__.py | 3 +
huobi/model/algo/cancel_order_result.py | 17 +
huobi/model/algo/order_history_item.py | 51 +
huobi/model/algo/order_list_item.py | 73 +
huobi/model/etf/__init__.py | 4 +
huobi/model/etf/etf_swap_config.py | 48 +
huobi/model/etf/etf_swap_in_out.py | 19 +
huobi/model/etf/etf_swap_list.py | 88 +
huobi/model/etf/unitprice.py | 10 +
huobi/model/generic/__init__.py | 5 +
huobi/model/generic/chain.py | 69 +
huobi/model/generic/exchange_info.py | 12 +
huobi/model/generic/market_status.py | 20 +
huobi/model/generic/reference_currency.py | 26 +
huobi/model/generic/symbol.py | 66 +
huobi/model/margin/__init__.py | 8 +
.../margin/cross_margin_account_balance.py | 49 +
huobi/model/margin/cross_margin_loan_ino.py | 9 +
.../model/margin/general_repay_loan_record.py | 59 +
.../model/margin/general_repay_loan_result.py | 31 +
huobi/model/margin/loan_ino.py | 30 +
huobi/model/margin/loan_order.py | 62 +
huobi/model/margin/margin_account_balance.py | 41 +
huobi/model/margin/margin_loan_ino.py | 40 +
huobi/model/market/__init__.py | 26 +
huobi/model/market/candlestick.py | 41 +
huobi/model/market/candlestick_event.py | 26 +
huobi/model/market/candlestick_req.py | 27 +
huobi/model/market/depth_entry.py | 25 +
huobi/model/market/last_trade_bestquote.py | 22 +
huobi/model/market/market_detail.py | 38 +
huobi/model/market/market_detail_event.py | 22 +
huobi/model/market/market_detail_merged.py | 41 +
huobi/model/market/market_detail_req.py | 22 +
huobi/model/market/market_ticker.py | 47 +
huobi/model/market/mbp.py | 54 +
huobi/model/market/mbp_full_event.py | 33 +
huobi/model/market/mbp_increase_event.py | 34 +
huobi/model/market/mbp_req.py | 36 +
huobi/model/market/pricedepth.py | 59 +
huobi/model/market/pricedepth_bbo.py | 34 +
huobi/model/market/pricedepth_bbo_event.py | 25 +
huobi/model/market/pricedepth_event.py | 23 +
huobi/model/market/pricedepth_req.py | 22 +
huobi/model/market/trade.py | 29 +
huobi/model/market/trade_detail.py | 29 +
huobi/model/market/trade_detail_event.py | 28 +
huobi/model/market/trade_detail_req.py | 23 +
huobi/model/subuser/__init__.py | 5 +
.../subuser/subuser_apikey_generation.py | 26 +
.../subuser/subuser_apikey_modification.py | 20 +
huobi/model/subuser/subuser_creation.py | 27 +
.../model/subuser/subuser_transferability.py | 20 +
huobi/model/subuser/trade_market.py | 21 +
huobi/model/subuser/user_apikey_info.py | 37 +
huobi/model/trade/__init__.py | 17 +
huobi/model/trade/batch_cancel_count.py | 23 +
huobi/model/trade/batch_cancel_result.py | 17 +
huobi/model/trade/batch_create_order.py | 23 +
huobi/model/trade/feerate.py | 22 +
huobi/model/trade/matchresult.py | 58 +
huobi/model/trade/order.py | 86 +
huobi/model/trade/order_detail_req.py | 29 +
huobi/model/trade/order_list_item.py | 55 +
huobi/model/trade/order_list_req.py | 29 +
huobi/model/trade/order_update.py | 56 +
huobi/model/trade/order_update_event.py | 23 +
huobi/model/trade/trade_clearing.py | 60 +
huobi/model/trade/trade_clearing_event.py | 32 +
huobi/model/trade/transact_feerate.py | 27 +
huobi/model/wallet/__init__.py | 7 +
huobi/model/wallet/chain_deposit_address.py | 25 +
huobi/model/wallet/chain_withdraw_address.py | 25 +
huobi/model/wallet/deposit.py | 48 +
huobi/model/wallet/deposit_history.py | 21 +
huobi/model/wallet/deposit_history_item.py | 42 +
huobi/model/wallet/withdraw.py | 48 +
huobi/model/wallet/withdraw_quota.py | 37 +
huobi/service/__init__.py | 0
huobi/service/account/__init__.py | 0
huobi/service/account/error_code.md | 13 +
.../account/get_account_asset_valuation.py | 38 +
.../account/get_account_balance_by_subuid.py | 22 +
huobi/service/account/get_account_history.py | 30 +
huobi/service/account/get_account_ledger.py | 36 +
huobi/service/account/get_account_point.py | 19 +
huobi/service/account/get_accounts.py | 50 +
.../account/get_aggregate_subuser_balance.py | 26 +
huobi/service/account/get_balance.py | 66 +
.../service/account/post_account_transfer.py | 41 +
.../account/post_futures_and_pro_transfer.py | 23 +
huobi/service/account/post_point_transfer.py | 19 +
.../account/post_sub_uid_management.py | 24 +
.../account/post_subaccount_transfer.py | 24 +
huobi/service/account/req_account_balance.py | 34 +
.../service/account/sub_account_update_v2.py | 30 +
huobi/service/algo/__init__.py | 0
huobi/service/algo/get_open_orders.py | 41 +
huobi/service/algo/get_order_by_cid.py | 19 +
huobi/service/algo/get_order_history.py | 19 +
huobi/service/algo/post_cancel_orders.py | 20 +
huobi/service/algo/post_create_order.py | 18 +
huobi/service/etf/__init__.py | 0
huobi/service/etf/get_etf_swap_config.py | 26 +
huobi/service/etf/get_etf_swap_list.py | 23 +
huobi/service/etf/post_etf_swap_in.py | 28 +
huobi/service/etf/post_etf_swap_out.py | 25 +
huobi/service/generic/__init__.py | 0
.../generic/get_exchange_currencies.py | 23 +
huobi/service/generic/get_exchange_symbols.py | 19 +
.../service/generic/get_exchange_timestamp.py | 24 +
huobi/service/generic/get_market_status.py | 18 +
.../generic/get_reference_currencies.py | 31 +
huobi/service/generic/get_system_status.py | 23 +
huobi/service/linear-swap/__init__.py | 0
.../linear-swap/post_swap_openorders.py | 69 +
huobi/service/margin/__init__.py | 0
.../get_cross_margin_account_balance.py | 25 +
.../margin/get_cross_margin_loan_info.py | 25 +
.../margin/get_cross_margin_loan_orders.py | 26 +
.../get_general_repayment_loan_records.py | 22 +
.../margin/get_margin_account_balance.py | 32 +
huobi/service/margin/get_margin_loan_info.py | 25 +
.../service/margin/get_margin_loan_orders.py | 26 +
.../margin/post_create_margin_order.py | 23 +
.../post_cross_margin_create_loan_orders.py | 23 +
.../post_cross_margin_loan_order_repay.py | 22 +
.../margin/post_cross_margin_transfer_in.py | 24 +
.../margin/post_cross_margin_transfer_out.py | 24 +
.../service/margin/post_general_repay_loan.py | 21 +
.../service/margin/post_repay_margin_order.py | 26 +
.../service/margin/post_transfer_in_margin.py | 23 +
.../margin/post_transfer_out_margin.py | 23 +
huobi/service/market/__init__.py | 1 +
huobi/service/market/get_candlestick.py | 25 +
huobi/service/market/get_history_trade.py | 35 +
huobi/service/market/get_market_detail.py | 26 +
.../market/get_market_detail_merged.py | 26 +
huobi/service/market/get_market_tickers.py | 25 +
huobi/service/market/get_market_trade.py | 26 +
huobi/service/market/get_pricedepth.py | 24 +
huobi/service/market/req_candlestick.py | 34 +
huobi/service/market/req_market_detail.py | 31 +
huobi/service/market/req_mbp.py | 27 +
huobi/service/market/req_pricedepth.py | 36 +
huobi/service/market/req_trade_detail.py | 29 +
huobi/service/market/sub_candlestick.py | 33 +
huobi/service/market/sub_market_detail.py | 31 +
huobi/service/market/sub_mbp_full.py | 27 +
huobi/service/market/sub_mbp_increase.py | 30 +
huobi/service/market/sub_pricedepth.py | 34 +
huobi/service/market/sub_pricedepth_bbo.py | 29 +
huobi/service/market/sub_trade_detail.py | 32 +
huobi/service/subuser/__init__.py | 0
huobi/service/subuser/get_uid.py | 20 +
huobi/service/subuser/get_user_apikey_info.py | 18 +
huobi/service/subuser/post_create_subuser.py | 18 +
.../subuser/post_set_transferability.py | 18 +
.../subuser/post_subuser_apikey_deletion.py | 17 +
.../subuser/post_subuser_apikey_generation.py | 18 +
.../post_subuser_apikey_modification.py | 18 +
huobi/service/subuser/post_tradable_market.py | 17 +
huobi/service/trade/__init__.py | 0
huobi/service/trade/get_feerate.py | 25 +
huobi/service/trade/get_history_orders.py | 24 +
huobi/service/trade/get_match_results.py | 25 +
.../trade/get_match_results_by_order_id.py | 60 +
huobi/service/trade/get_open_orders.py | 41 +
.../trade/get_order_by_client_order_id.py | 35 +
huobi/service/trade/get_order_by_id.py | 59 +
huobi/service/trade/get_orders.py | 25 +
huobi/service/trade/get_transact_feerate.py | 25 +
.../trade/post_batch_cancel_open_order.py | 56 +
.../service/trade/post_batch_cancel_order.py | 38 +
.../service/trade/post_batch_create_order.py | 32 +
.../service/trade/post_cancel_client_order.py | 33 +
huobi/service/trade/post_cancel_order.py | 49 +
huobi/service/trade/post_create_order.py | 57 +
.../trade/post_transfer_futures_pro.py | 25 +
huobi/service/trade/req_order_detail.py | 35 +
huobi/service/trade/req_order_list.py | 38 +
huobi/service/trade/sub_order_update_v2.py | 35 +
huobi/service/trade/sub_trade_clearing_v2.py | 35 +
huobi/service/wallet/__init__.py | 0
.../wallet/get_account_deposit_address.py | 25 +
.../wallet/get_account_withdraw_address.py | 25 +
.../wallet/get_account_withdraw_quota.py | 26 +
huobi/service/wallet/get_deposit_withdraw.py | 30 +
.../wallet/get_sub_user_deposit_address.py | 22 +
.../wallet/get_sub_user_deposit_history.py | 26 +
huobi/service/wallet/post_cancel_withdraw.py | 28 +
huobi/service/wallet/post_create_withdraw.py | 26 +
huobi/utils/__init__.py | 11 +
huobi/utils/api_signature.py | 36 +
huobi/utils/api_signature_v2.py | 60 +
huobi/utils/channel_parser.py | 5 +
huobi/utils/channels.py | 83 +
huobi/utils/channels_request.py | 79 +
huobi/utils/etf_result.py | 29 +
huobi/utils/input_checker.py | 90 +
huobi/utils/json_parser.py | 122 +
huobi/utils/log_info.py | 31 +
huobi/utils/print_mix_object.py | 232 ++
huobi/utils/time_service.py | 22 +
huobi/utils/url_params_builder.py | 33 +
huobi_alert.py | 53 +
k8s.md | 57 +
main.dev.py | 31 +
main.py | 46 +
requirements.txt | 6 +
test.py | 33 +
test1.py | 17 +
test2.py | 7 +
test_depth.py | 34 +
utils/__init__.py | 4 +
utils/config.py | 54 +
utils/dingding.py | 34 +
utils/queue.py | 52 +
utils/smtp.py | 61 +
utils/utility.py | 110 +
392 files changed, 18954 insertions(+)
create mode 100644 .drone.yml
create mode 100644 .gitignore
create mode 100644 Dockerfile
create mode 100644 Dockerfile-requirements
create mode 100644 README.md
create mode 100644 __init__.py
create mode 100644 bakreq.txt
create mode 100644 binance/__init__.py
create mode 100644 binance/binance_constant.py
create mode 100644 binance/binance_future.py
create mode 100644 binance/binance_future_trader.py
create mode 100644 binance/binance_spot.py
create mode 100644 binance/binance_trader.py
create mode 100644 binance/trade.txt
create mode 100644 binance/trader_bak
create mode 100644 conf/config-example.json
create mode 100644 conf_huobi/config-example.json
create mode 100644 docker_build.md
create mode 100644 example/__init__.py
create mode 100644 example/account/get_account_asset_valuation.py
create mode 100644 example/account/get_account_balance.py
create mode 100644 example/account/get_account_balance_by_subuid.py
create mode 100644 example/account/get_account_balance_sufficient.py
create mode 100644 example/account/get_account_by_type_symbol.py
create mode 100644 example/account/get_account_history.py
create mode 100644 example/account/get_account_ledger.py
create mode 100644 example/account/get_account_point.py
create mode 100644 example/account/get_accounts.py
create mode 100644 example/account/get_aggregated_subuser_balance.py
create mode 100644 example/account/get_balance.py
create mode 100644 example/account/post_account_transfer.py
create mode 100644 example/account/post_point_transfer.py
create mode 100644 example/account/post_sub_user_management.py
create mode 100644 example/account/post_transfer_between_futures_and_pro.py
create mode 100644 example/account/post_transfer_between_parent_and_subuser.py
create mode 100644 example/account/req_account_balance_list.py
create mode 100644 example/account/sub_account_update.py
create mode 100644 example/algo/get_open_orders.py
create mode 100644 example/algo/get_order.py
create mode 100644 example/algo/get_order_history.py
create mode 100644 example/algo/post_cancel_algo_orders.py
create mode 100644 example/algo/post_create_algo_order.py
create mode 100644 example/api_key.py
create mode 100644 example/etf/get_etf_swap_config.py
create mode 100644 example/etf/get_etf_swap_list.py
create mode 100644 example/etf/post_etf_swap_in.py
create mode 100644 example/etf/post_etf_swap_out.py
create mode 100644 example/generic/get_exchange_currencies.py
create mode 100644 example/generic/get_exchange_info.py
create mode 100644 example/generic/get_exchange_symbols.py
create mode 100644 example/generic/get_exchange_timestamp.py
create mode 100644 example/generic/get_market_status.py
create mode 100644 example/generic/get_reference_currencies.py
create mode 100644 example/generic/get_system_status.py
create mode 100644 example/margin/get_cross_margin_account_balance.py
create mode 100644 example/margin/get_cross_margin_loan_info.py
create mode 100644 example/margin/get_cross_margin_loan_orders.py
create mode 100644 example/margin/get_general_repayment_loan_records.py
create mode 100644 example/margin/get_margin_account_balance.py
create mode 100644 example/margin/get_margin_loan_info.py
create mode 100644 example/margin/get_margin_loan_orders.py
create mode 100644 example/margin/post_cross_margin_create_loan_orders.py
create mode 100644 example/margin/post_cross_margin_loan_order_repay.py
create mode 100644 example/margin/post_cross_margin_transfer.py
create mode 100644 example/margin/post_general_repay_loan.py
create mode 100644 example/margin/post_margin_create_order.py
create mode 100644 example/margin/post_margin_repay_order.py
create mode 100644 example/margin/post_margin_transfer_in.py
create mode 100644 example/margin/post_margin_transfer_out.py
create mode 100644 example/market/get_candlestick.py
create mode 100644 example/market/get_history_trade.py
create mode 100644 example/market/get_market_detail.py
create mode 100644 example/market/get_market_detail_merged.py
create mode 100644 example/market/get_market_tickers.py
create mode 100644 example/market/get_market_trade.py
create mode 100644 example/market/get_pricedepth.py
create mode 100644 example/market/req_candlestick.py
create mode 100644 example/market/req_market_detail.py
create mode 100644 example/market/req_mbp.py
create mode 100644 example/market/req_pricedepth.py
create mode 100644 example/market/req_trade_detail.py
create mode 100644 example/market/sub_candlestick.py
create mode 100644 example/market/sub_market_detail.py
create mode 100644 example/market/sub_mbp_full.py
create mode 100644 example/market/sub_mbp_increase.py
create mode 100644 example/market/sub_pricedepth.py
create mode 100644 example/market/sub_pricedepth_bbo.py
create mode 100644 example/market/sub_trade_detail.py
create mode 100644 example/subuser/get_uid.py
create mode 100644 example/subuser/get_user_apikey_info.py
create mode 100644 example/subuser/post_create_subuser.py
create mode 100644 example/subuser/post_set_subuser_transferability.py
create mode 100644 example/subuser/post_subuser_apikey_deletion.py
create mode 100644 example/subuser/post_subuser_apikey_generation.py
create mode 100644 example/subuser/post_subuser_apikey_modification.py
create mode 100644 example/subuser/post_trade_market.py
create mode 100644 example/trade/get_feerate.py
create mode 100644 example/trade/get_history_orders_in_48hours.py
create mode 100644 example/trade/get_matchresult.py
create mode 100644 example/trade/get_matchresult_by_order_id.py
create mode 100644 example/trade/get_open_orders.py
create mode 100644 example/trade/get_order.py
create mode 100644 example/trade/get_order_by_client_order_id.py
create mode 100644 example/trade/get_orders.py
create mode 100644 example/trade/get_transact_feerate.py
create mode 100644 example/trade/post_batch_cancel_open_order.py
create mode 100644 example/trade/post_batch_cancel_order.py
create mode 100644 example/trade/post_batch_create_order.py
create mode 100644 example/trade/post_cancel_client_order.py
create mode 100644 example/trade/post_cancel_order.py
create mode 100644 example/trade/post_client_order_id.py
create mode 100644 example/trade/post_create_order.py
create mode 100644 example/trade/post_transfer_futures_pro.py
create mode 100644 example/trade/req_order_detail.py
create mode 100644 example/trade/req_order_list.py
create mode 100644 example/trade/sub_order_update.py
create mode 100644 example/trade/sub_trade_clearing.py
create mode 100644 example/wallet/get_account_deposit_address.py
create mode 100644 example/wallet/get_account_withdraw_address.py
create mode 100644 example/wallet/get_account_withdraw_quota.py
create mode 100644 example/wallet/get_deposit_withdraw_list.py
create mode 100644 example/wallet/get_sub_user_deposit_address.py
create mode 100644 example/wallet/get_sub_user_deposit_history.py
create mode 100644 example/wallet/post_withdraw_and_cancel.py
create mode 100644 huobi/__init__.py
create mode 100644 huobi/client/__init__.py
create mode 100644 huobi/client/account.py
create mode 100644 huobi/client/algo.py
create mode 100644 huobi/client/etf.py
create mode 100644 huobi/client/generic.py
create mode 100644 huobi/client/linear_swap.py
create mode 100644 huobi/client/margin.py
create mode 100644 huobi/client/market.py
create mode 100644 huobi/client/subuser.py
create mode 100644 huobi/client/trade.py
create mode 100644 huobi/client/wallet.py
create mode 100644 huobi/connection/__init__.py
create mode 100644 huobi/connection/impl/__init__.py
create mode 100644 huobi/connection/impl/private_def.py
create mode 100644 huobi/connection/impl/restapi_invoker.py
create mode 100644 huobi/connection/impl/restapi_request.py
create mode 100644 huobi/connection/impl/websocket_manage.py
create mode 100644 huobi/connection/impl/websocket_request.py
create mode 100644 huobi/connection/impl/websocket_watchdog.py
create mode 100644 huobi/connection/restapi_sync_client.py
create mode 100644 huobi/connection/subscribe_client.py
create mode 100644 huobi/connection/websocket_req_client.py
create mode 100644 huobi/constant/__init__.py
create mode 100644 huobi/constant/definition.py
create mode 100644 huobi/constant/result.py
create mode 100644 huobi/constant/system.py
create mode 100644 huobi/constant/test.py
create mode 100644 huobi/exception/__init__.py
create mode 100644 huobi/exception/huobi_api_exception.py
create mode 100644 huobi/model/__init__.py
create mode 100644 huobi/model/account/__init__.py
create mode 100644 huobi/model/account/account.py
create mode 100644 huobi/model/account/account_asset_valuation.py
create mode 100644 huobi/model/account/account_balance.py
create mode 100644 huobi/model/account/account_balance_req.py
create mode 100644 huobi/model/account/account_history.py
create mode 100644 huobi/model/account/account_ledger.py
create mode 100644 huobi/model/account/account_point_group.py
create mode 100644 huobi/model/account/account_point_result.py
create mode 100644 huobi/model/account/account_point_transfer_result.py
create mode 100644 huobi/model/account/account_transfer_result.py
create mode 100644 huobi/model/account/account_update.py
create mode 100644 huobi/model/account/account_update_event.py
create mode 100644 huobi/model/account/balance.py
create mode 100644 huobi/model/account/complete_subaccount.py
create mode 100644 huobi/model/account/margin_balance_detail.py
create mode 100644 huobi/model/account/sub_uid_management.py
create mode 100644 huobi/model/algo/__init__.py
create mode 100644 huobi/model/algo/cancel_order_result.py
create mode 100644 huobi/model/algo/order_history_item.py
create mode 100644 huobi/model/algo/order_list_item.py
create mode 100644 huobi/model/etf/__init__.py
create mode 100644 huobi/model/etf/etf_swap_config.py
create mode 100644 huobi/model/etf/etf_swap_in_out.py
create mode 100644 huobi/model/etf/etf_swap_list.py
create mode 100644 huobi/model/etf/unitprice.py
create mode 100644 huobi/model/generic/__init__.py
create mode 100644 huobi/model/generic/chain.py
create mode 100644 huobi/model/generic/exchange_info.py
create mode 100644 huobi/model/generic/market_status.py
create mode 100644 huobi/model/generic/reference_currency.py
create mode 100644 huobi/model/generic/symbol.py
create mode 100644 huobi/model/margin/__init__.py
create mode 100644 huobi/model/margin/cross_margin_account_balance.py
create mode 100644 huobi/model/margin/cross_margin_loan_ino.py
create mode 100644 huobi/model/margin/general_repay_loan_record.py
create mode 100644 huobi/model/margin/general_repay_loan_result.py
create mode 100644 huobi/model/margin/loan_ino.py
create mode 100644 huobi/model/margin/loan_order.py
create mode 100644 huobi/model/margin/margin_account_balance.py
create mode 100644 huobi/model/margin/margin_loan_ino.py
create mode 100644 huobi/model/market/__init__.py
create mode 100644 huobi/model/market/candlestick.py
create mode 100644 huobi/model/market/candlestick_event.py
create mode 100644 huobi/model/market/candlestick_req.py
create mode 100644 huobi/model/market/depth_entry.py
create mode 100644 huobi/model/market/last_trade_bestquote.py
create mode 100644 huobi/model/market/market_detail.py
create mode 100644 huobi/model/market/market_detail_event.py
create mode 100644 huobi/model/market/market_detail_merged.py
create mode 100644 huobi/model/market/market_detail_req.py
create mode 100644 huobi/model/market/market_ticker.py
create mode 100644 huobi/model/market/mbp.py
create mode 100644 huobi/model/market/mbp_full_event.py
create mode 100644 huobi/model/market/mbp_increase_event.py
create mode 100644 huobi/model/market/mbp_req.py
create mode 100644 huobi/model/market/pricedepth.py
create mode 100644 huobi/model/market/pricedepth_bbo.py
create mode 100644 huobi/model/market/pricedepth_bbo_event.py
create mode 100644 huobi/model/market/pricedepth_event.py
create mode 100644 huobi/model/market/pricedepth_req.py
create mode 100644 huobi/model/market/trade.py
create mode 100644 huobi/model/market/trade_detail.py
create mode 100644 huobi/model/market/trade_detail_event.py
create mode 100644 huobi/model/market/trade_detail_req.py
create mode 100644 huobi/model/subuser/__init__.py
create mode 100644 huobi/model/subuser/subuser_apikey_generation.py
create mode 100644 huobi/model/subuser/subuser_apikey_modification.py
create mode 100644 huobi/model/subuser/subuser_creation.py
create mode 100644 huobi/model/subuser/subuser_transferability.py
create mode 100644 huobi/model/subuser/trade_market.py
create mode 100644 huobi/model/subuser/user_apikey_info.py
create mode 100644 huobi/model/trade/__init__.py
create mode 100644 huobi/model/trade/batch_cancel_count.py
create mode 100644 huobi/model/trade/batch_cancel_result.py
create mode 100644 huobi/model/trade/batch_create_order.py
create mode 100644 huobi/model/trade/feerate.py
create mode 100644 huobi/model/trade/matchresult.py
create mode 100644 huobi/model/trade/order.py
create mode 100644 huobi/model/trade/order_detail_req.py
create mode 100644 huobi/model/trade/order_list_item.py
create mode 100644 huobi/model/trade/order_list_req.py
create mode 100644 huobi/model/trade/order_update.py
create mode 100644 huobi/model/trade/order_update_event.py
create mode 100644 huobi/model/trade/trade_clearing.py
create mode 100644 huobi/model/trade/trade_clearing_event.py
create mode 100644 huobi/model/trade/transact_feerate.py
create mode 100644 huobi/model/wallet/__init__.py
create mode 100644 huobi/model/wallet/chain_deposit_address.py
create mode 100644 huobi/model/wallet/chain_withdraw_address.py
create mode 100644 huobi/model/wallet/deposit.py
create mode 100644 huobi/model/wallet/deposit_history.py
create mode 100644 huobi/model/wallet/deposit_history_item.py
create mode 100644 huobi/model/wallet/withdraw.py
create mode 100644 huobi/model/wallet/withdraw_quota.py
create mode 100644 huobi/service/__init__.py
create mode 100644 huobi/service/account/__init__.py
create mode 100644 huobi/service/account/error_code.md
create mode 100644 huobi/service/account/get_account_asset_valuation.py
create mode 100644 huobi/service/account/get_account_balance_by_subuid.py
create mode 100644 huobi/service/account/get_account_history.py
create mode 100644 huobi/service/account/get_account_ledger.py
create mode 100644 huobi/service/account/get_account_point.py
create mode 100644 huobi/service/account/get_accounts.py
create mode 100644 huobi/service/account/get_aggregate_subuser_balance.py
create mode 100644 huobi/service/account/get_balance.py
create mode 100644 huobi/service/account/post_account_transfer.py
create mode 100644 huobi/service/account/post_futures_and_pro_transfer.py
create mode 100644 huobi/service/account/post_point_transfer.py
create mode 100644 huobi/service/account/post_sub_uid_management.py
create mode 100644 huobi/service/account/post_subaccount_transfer.py
create mode 100644 huobi/service/account/req_account_balance.py
create mode 100644 huobi/service/account/sub_account_update_v2.py
create mode 100644 huobi/service/algo/__init__.py
create mode 100644 huobi/service/algo/get_open_orders.py
create mode 100644 huobi/service/algo/get_order_by_cid.py
create mode 100644 huobi/service/algo/get_order_history.py
create mode 100644 huobi/service/algo/post_cancel_orders.py
create mode 100644 huobi/service/algo/post_create_order.py
create mode 100644 huobi/service/etf/__init__.py
create mode 100644 huobi/service/etf/get_etf_swap_config.py
create mode 100644 huobi/service/etf/get_etf_swap_list.py
create mode 100644 huobi/service/etf/post_etf_swap_in.py
create mode 100644 huobi/service/etf/post_etf_swap_out.py
create mode 100644 huobi/service/generic/__init__.py
create mode 100644 huobi/service/generic/get_exchange_currencies.py
create mode 100644 huobi/service/generic/get_exchange_symbols.py
create mode 100644 huobi/service/generic/get_exchange_timestamp.py
create mode 100644 huobi/service/generic/get_market_status.py
create mode 100644 huobi/service/generic/get_reference_currencies.py
create mode 100644 huobi/service/generic/get_system_status.py
create mode 100644 huobi/service/linear-swap/__init__.py
create mode 100644 huobi/service/linear-swap/post_swap_openorders.py
create mode 100644 huobi/service/margin/__init__.py
create mode 100644 huobi/service/margin/get_cross_margin_account_balance.py
create mode 100644 huobi/service/margin/get_cross_margin_loan_info.py
create mode 100644 huobi/service/margin/get_cross_margin_loan_orders.py
create mode 100644 huobi/service/margin/get_general_repayment_loan_records.py
create mode 100644 huobi/service/margin/get_margin_account_balance.py
create mode 100644 huobi/service/margin/get_margin_loan_info.py
create mode 100644 huobi/service/margin/get_margin_loan_orders.py
create mode 100644 huobi/service/margin/post_create_margin_order.py
create mode 100644 huobi/service/margin/post_cross_margin_create_loan_orders.py
create mode 100644 huobi/service/margin/post_cross_margin_loan_order_repay.py
create mode 100644 huobi/service/margin/post_cross_margin_transfer_in.py
create mode 100644 huobi/service/margin/post_cross_margin_transfer_out.py
create mode 100644 huobi/service/margin/post_general_repay_loan.py
create mode 100644 huobi/service/margin/post_repay_margin_order.py
create mode 100644 huobi/service/margin/post_transfer_in_margin.py
create mode 100644 huobi/service/margin/post_transfer_out_margin.py
create mode 100644 huobi/service/market/__init__.py
create mode 100644 huobi/service/market/get_candlestick.py
create mode 100644 huobi/service/market/get_history_trade.py
create mode 100644 huobi/service/market/get_market_detail.py
create mode 100644 huobi/service/market/get_market_detail_merged.py
create mode 100644 huobi/service/market/get_market_tickers.py
create mode 100644 huobi/service/market/get_market_trade.py
create mode 100644 huobi/service/market/get_pricedepth.py
create mode 100644 huobi/service/market/req_candlestick.py
create mode 100644 huobi/service/market/req_market_detail.py
create mode 100644 huobi/service/market/req_mbp.py
create mode 100644 huobi/service/market/req_pricedepth.py
create mode 100644 huobi/service/market/req_trade_detail.py
create mode 100644 huobi/service/market/sub_candlestick.py
create mode 100644 huobi/service/market/sub_market_detail.py
create mode 100644 huobi/service/market/sub_mbp_full.py
create mode 100644 huobi/service/market/sub_mbp_increase.py
create mode 100644 huobi/service/market/sub_pricedepth.py
create mode 100644 huobi/service/market/sub_pricedepth_bbo.py
create mode 100644 huobi/service/market/sub_trade_detail.py
create mode 100644 huobi/service/subuser/__init__.py
create mode 100644 huobi/service/subuser/get_uid.py
create mode 100644 huobi/service/subuser/get_user_apikey_info.py
create mode 100644 huobi/service/subuser/post_create_subuser.py
create mode 100644 huobi/service/subuser/post_set_transferability.py
create mode 100644 huobi/service/subuser/post_subuser_apikey_deletion.py
create mode 100644 huobi/service/subuser/post_subuser_apikey_generation.py
create mode 100644 huobi/service/subuser/post_subuser_apikey_modification.py
create mode 100644 huobi/service/subuser/post_tradable_market.py
create mode 100644 huobi/service/trade/__init__.py
create mode 100644 huobi/service/trade/get_feerate.py
create mode 100644 huobi/service/trade/get_history_orders.py
create mode 100644 huobi/service/trade/get_match_results.py
create mode 100644 huobi/service/trade/get_match_results_by_order_id.py
create mode 100644 huobi/service/trade/get_open_orders.py
create mode 100644 huobi/service/trade/get_order_by_client_order_id.py
create mode 100644 huobi/service/trade/get_order_by_id.py
create mode 100644 huobi/service/trade/get_orders.py
create mode 100644 huobi/service/trade/get_transact_feerate.py
create mode 100644 huobi/service/trade/post_batch_cancel_open_order.py
create mode 100644 huobi/service/trade/post_batch_cancel_order.py
create mode 100644 huobi/service/trade/post_batch_create_order.py
create mode 100644 huobi/service/trade/post_cancel_client_order.py
create mode 100644 huobi/service/trade/post_cancel_order.py
create mode 100644 huobi/service/trade/post_create_order.py
create mode 100644 huobi/service/trade/post_transfer_futures_pro.py
create mode 100644 huobi/service/trade/req_order_detail.py
create mode 100644 huobi/service/trade/req_order_list.py
create mode 100644 huobi/service/trade/sub_order_update_v2.py
create mode 100644 huobi/service/trade/sub_trade_clearing_v2.py
create mode 100644 huobi/service/wallet/__init__.py
create mode 100644 huobi/service/wallet/get_account_deposit_address.py
create mode 100644 huobi/service/wallet/get_account_withdraw_address.py
create mode 100644 huobi/service/wallet/get_account_withdraw_quota.py
create mode 100644 huobi/service/wallet/get_deposit_withdraw.py
create mode 100644 huobi/service/wallet/get_sub_user_deposit_address.py
create mode 100644 huobi/service/wallet/get_sub_user_deposit_history.py
create mode 100644 huobi/service/wallet/post_cancel_withdraw.py
create mode 100644 huobi/service/wallet/post_create_withdraw.py
create mode 100644 huobi/utils/__init__.py
create mode 100644 huobi/utils/api_signature.py
create mode 100644 huobi/utils/api_signature_v2.py
create mode 100644 huobi/utils/channel_parser.py
create mode 100644 huobi/utils/channels.py
create mode 100644 huobi/utils/channels_request.py
create mode 100644 huobi/utils/etf_result.py
create mode 100644 huobi/utils/input_checker.py
create mode 100644 huobi/utils/json_parser.py
create mode 100644 huobi/utils/log_info.py
create mode 100644 huobi/utils/print_mix_object.py
create mode 100644 huobi/utils/time_service.py
create mode 100644 huobi/utils/url_params_builder.py
create mode 100644 huobi_alert.py
create mode 100644 k8s.md
create mode 100644 main.dev.py
create mode 100644 main.py
create mode 100644 requirements.txt
create mode 100644 test.py
create mode 100644 test1.py
create mode 100644 test2.py
create mode 100644 test_depth.py
create mode 100644 utils/__init__.py
create mode 100644 utils/config.py
create mode 100644 utils/dingding.py
create mode 100644 utils/queue.py
create mode 100644 utils/smtp.py
create mode 100644 utils/utility.py
diff --git a/.drone.yml b/.drone.yml
new file mode 100644
index 0000000..6327199
--- /dev/null
+++ b/.drone.yml
@@ -0,0 +1,10 @@
+pipeline:
+ ssh:
+ image: 'me/sre/drone-ssh:20210519'
+ host: 172.16.0.22
+ username: root
+ password: 123456
+ port: 22
+ #username: deploy+ volumes:+ -/root/drone_rsa:/root/ssh/drone_rsa key_path:/root/ssh/drone_rsa
+ script:
+ - echo"test ssh1"
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2885d26
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,118 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+*.idea/*
+*.idea
+*.iml
+# C extensions
+*.so
+.DS_Store
+config.json
+venv
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+nohub.out
+myquant.txt
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.idea
+.idea/*
+
+# log file
+grid_trader_log.txt
+*.log
+
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..337e179
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,7 @@
+#mmmmmmmmmmmm/binance_grid_trader:67
+FROM python:3.9
+#RUN pip install -r requirements.txt
+WORKDIR /app
+ADD . /app
+RUN python -m pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
+CMD ["python", "main.py"]
\ No newline at end of file
diff --git a/Dockerfile-requirements b/Dockerfile-requirements
new file mode 100644
index 0000000..20ea662
--- /dev/null
+++ b/Dockerfile-requirements
@@ -0,0 +1,5 @@
+#mmmmmmmmmmmmmmmmmmmmmmmmm/binance_grid_trader_requirements:5
+FROM python:3.9
+
+RUN pip install --no-cache-dir -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
+RUN pip install -r requirements.txt
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c0e8b21
--- /dev/null
+++ b/README.md
@@ -0,0 +1,118 @@
+
+# 配置 文件`config.json`说明
+
+
+
+| 配置 | 说明 |
+| ----------- | ----------- |
+| sleep_time | 循环间隔 |
+| cancel_time | 取消过期订单间隔 |
+| platform | 交易类型 现货交易 **binance_spot** 或者 合约交易**binance_future** |
+|symbol | 交易对: BTCUSDT, BNBUSDT等 |
+|api_key | 从交易所获取 |
+|api_secret | 交易所获取 |
+|profit_scroll | 滚动止盈比例,比如 1.05 表示触发滚动止盈后将卖单价格提到1.05被再挂上|
+|profit_intend | 滚动触发比例,比如0.95 表示当前价格达到卖单价格的0.95后,触发滚动 |
+|deficit_scroll | 滚动止损比例,比如0.9 表示在触发滚动止盈时候,同时将止损价设置为当前价格的0.9 |
+|gap_percent | 期望利润率,网格交易的价格间隙
buy_price = round_to(float(check_order.get("price")) * (1 - float(config.gap_percent)),
sell_price = round_to(float(check_order.get("price")) * (1 + float(config.gap_percent)), float(config.min_price))
越大单次利润率越高,越小越容易成交 最好不超过1% |
+|quantity | 每次下单的数量 比如50个XRP |
+|min_price | 价格波动的最小单位, 用来计算价格精度: 如
XRPUSDT 0.00001
BTCUSDT 是0.01
BNBUSDT是0.0001
ETHUSDT 是0.01
这个价格要从交易所查看,每个交易对不一样。|
+|price_stop_to_buy | 抛仓价,高于这个就不要买了 |
+|price_stop_to_sell | 清仓价,低于这个就不要卖了 |
+|min_qty | 最小的下单量
现货要求最小下单是10USDT等值的币
XRPUSDT的话 10USDT大概40个XRP
而对于合约来说, BTCUSDT要求是0.001个BTC |
+|max_orders | 最多允许的挂买单数量
超过该值时候 删除最高价的一个买单|
+|max_sell_orders|卖单的上限,达到上限之后不再创建买单;但是不影响创建卖单|
+|proxy_host | 如果需要用代理的话,请填写你的代理IP |
+|proxy_port | 代理端口号 |
+|dingding_robot_url | 钉钉机器人的地址 |
+|dingding_user_phone | 自己在钉钉群的手机号 |
+|user_email | 邮件接收地址 |
+|SMTP_HOST | 邮件服务器 |
+|SMTP_PORT | 邮件服务器端口 |
+|SMTP_USER | 邮件服务器发信邮箱 |
+|SMTP_PASSWORD | 邮件服务器发信邮箱密码 |
+
+
+
+
+例如:
+
+```json
+{
+ "platform": "binance_spot",
+ "symbol": "LINKUSDT",
+ "api_key": "11111111111111111111111111111",
+ "api_secret": "2222222222222222222222222",
+ "gap_percent": 0.005,
+ "quantity": 5,
+ "min_price": 0.0001,
+ "price_stop_to_buy": 22,
+ "price_stop_to_sell": 14,
+ "min_qty": 5,
+ "max_orders": 10,
+ "max_sell_orders": 10,
+ "proxy_host": "",
+ "proxy_port": 0,
+ "dingding_robot_url": "https://oapi.dingtalk.com/robot/send?access_token=33333333333333333333333333333d29c",
+ "dingding_user_phone": "33333333333333333",
+ "user_email": "3333333333333333333333",
+ "SMTP_HOST": "33333333333333333333",
+ "SMTP_PORT": 80,
+ "SMTP_USER": "33333333333333333333333",
+ "SMTP_PASSWORD": "33333333333333333333333333"
+}
+
+```
+
+
+
+### start.sh
+```bash
+nohup python -u main.py > grid_nohup.out 2>&1 &
+```
+
+
+
+## 网格交易策略使用行情
+- 震荡行情
+- 适合币圈的高波动率的品种
+- 适合现货, 如果交易合约,需要注意防止极端行情爆仓。
+
+# 51bitquant网格交易策略
+https://github.com/51bitquant/binance_grid_trader
+
+
+网格交易的原理视频讲解链接:
+[https://www.bilibili.com/video/BV1Jg4y1v7vr/](https://www.bilibili.com/video/BV1Jg4y1v7vr/)
+
+
+视频讲解如下:
+[https://www.bilibili.com/video/BV1eK4y147HT/](https://www.bilibili.com/video/BV1eK4y147HT/)
+
+https://github.com/hengxuZ/binance-quantization
+# 币圈低风险套利赚钱-年化15%以上
+如何在币圈进行低风险的套利。
+
+
+## 买卖出入金的方式
+通过场外OTC,使用人民购买USDT,付给对方钱后,点击已付款,OTC商家会释放相应USDT给你。 在把法币的资产划转到币币账户进行交易相应的数字资产。
+
+相应的如果你想把数字资产换成法币,那么你把你的资产划转到法币,然后出售资产,在收到对方的钱,且确认是对方的账户转给你,数目也是对的情况下,点击已收款,然后释放对应的数字资产给商家。
+
+
+## 存币赚取利息
+ 通过存币,交易所会帮你把资产借贷给相应的人,然后对方需要支付相应的利息给你。
+
+## 挖矿赚利息
+类似DEFI,挖矿,或者CEFI挖矿的方式。为相应的交易对提供流动性,赚取对应的手续费
+
+## 永续资金费率套利
+在多头市场情况下,永续资金费率有的高达0.75%,一般情况下,有的资金费率在万1到千2之间,也有可能是负是资金费率。正的资金费率表示都头出资金费率,负的资金费率表示空方付对应的资金费率。
+
+## 远近合约跨期套利
+一般情况下,远期合约的价格币现货价格、永续合约或者近期的合约的价格要高。如果你买入现货,去对应的远期合约做空对应的资产,那么就相当于你把资产卖出一个较高的价格,等到他们价格相等或者接近的时候,再平仓。不过这个一般是要用程序去执行比较好。这样可以随时间监控他们之间的价差,捕捉更多的套利机会。
+
+## 持有平台币参与交易所的一些活动
+持有BNB或者OKB,参加他们平台的一些活动,比如最近的BNB要用来挖矿,类似之前的IEO活动。
+
+
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/bakreq.txt b/bakreq.txt
new file mode 100644
index 0000000..a3e92b7
--- /dev/null
+++ b/bakreq.txt
@@ -0,0 +1,6 @@
+requests==2.22.0
+dingtalkchatbot
+pytz
+APScheduler==3.6.3
+aiohttp==3.6.2
+websocket_client==0.57.0
\ No newline at end of file
diff --git a/binance/__init__.py b/binance/__init__.py
new file mode 100644
index 0000000..5b75099
--- /dev/null
+++ b/binance/__init__.py
@@ -0,0 +1,3 @@
+from .binance_constant import OrderType, OrderStatus, OrderSide, RequestMethod,Interval
+from .binance_spot import BinanceSpotHttp
+from .binance_future import BinanceFutureHttp
\ No newline at end of file
diff --git a/binance/binance_constant.py b/binance/binance_constant.py
new file mode 100644
index 0000000..ea757d3
--- /dev/null
+++ b/binance/binance_constant.py
@@ -0,0 +1,55 @@
+from enum import Enum
+
+class RequestMethod(Enum):
+ """
+ 请求的方法.
+ """
+ GET = 'GET'
+ POST = 'POST'
+ PUT = 'PUT'
+ DELETE = 'DELETE'
+
+
+
+class OrderStatus(Enum):
+ NEW = "NEW"
+ PARTIALLY_FILLED = "PARTIALLY_FILLED"
+ FILLED = "FILLED"
+ CANCELED = "CANCELED"
+ PENDING_CANCEL = "PENDING_CANCEL"
+ REJECTED = "REJECTED"
+ EXPIRED = "EXPIRED"
+
+
+class OrderType(Enum):
+ LIMIT = "LIMIT"
+ MARKET = "MARKET"
+ STOP = "STOP"
+
+
+
+class OrderSide(Enum):
+ BUY = "BUY"
+ SELL = "SELL"
+
+
+class Interval(Enum):
+ """
+ 请求的K线数据..
+ """
+ MINUTE_1 = '1m'
+ MINUTE_3 = '3m'
+ MINUTE_5 = '5m'
+ MINUTE_15 = '15m'
+ MINUTE_30 = '30m'
+ HOUR_1 = '1h'
+ HOUR_2 = '2h'
+ HOUR_4 = '4h'
+ HOUR_6 = '6h'
+ HOUR_8 = '8h'
+ HOUR_12 = '12h'
+ DAY_1 = '1d'
+ DAY_3 = '3d'
+ WEEK_1 = '1w'
+ MONTH_1 = '1M'
+
diff --git a/binance/binance_future.py b/binance/binance_future.py
new file mode 100644
index 0000000..0cb448b
--- /dev/null
+++ b/binance/binance_future.py
@@ -0,0 +1,345 @@
+from binance import OrderType, OrderStatus, OrderSide, RequestMethod,Interval
+import requests
+import time
+import hmac
+import hashlib
+from threading import Thread, Lock
+from datetime import datetime
+
+class BinanceFutureHttp(object):
+
+ def __init__(self, api_key=None, secret=None, host=None, proxy_host="", proxy_port=0, timeout=5, try_counts=5):
+ self.key = api_key
+ self.secret = secret
+ self.host = host if host else "https://fapi.binance.com"
+ self.recv_window = 5000
+ self.timeout = timeout
+ self.order_count_lock = Lock()
+ self.order_count = 1_000_000
+ self.try_counts = try_counts # 失败尝试的次数.
+ self.proxy_host = proxy_host
+ self.proxy_port = proxy_port
+
+ @property
+ def proxies(self):
+ if self.proxy_host and self.proxy_port:
+ proxy = f"http://{self.proxy_host}:{self.proxy_port}"
+ return {"http": proxy, "https": proxy}
+ return {}
+
+ def build_parameters(self, params: dict):
+ keys = list(params.keys())
+ keys.sort()
+ return '&'.join([f"{key}={params[key]}" for key in params.keys()])
+
+ def request(self, req_method: RequestMethod, path: str, requery_dict=None, verify=False):
+ url = self.host + path
+
+ if verify:
+ query_str = self._sign(requery_dict)
+ url += '?' + query_str
+ elif requery_dict:
+ url += '?' + self.build_parameters(requery_dict)
+ headers = {"X-MBX-APIKEY": self.key}
+
+ for i in range(0, self.try_counts):
+ try:
+ response = requests.request(req_method.value, url=url, headers=headers, timeout=self.timeout, proxies=self.proxies)
+ if response.status_code == 200:
+ return response.json()
+ else:
+ print(f"请求没有成功: {response.status_code}, 继续尝试请求")
+ except Exception as error:
+ print(f"请求:{path}, 发生了错误: {error}, 时间: {datetime.now()}")
+ time.sleep(3)
+
+ def server_time(self):
+ path = '/fapi/v1/time'
+ return self.request(req_method=RequestMethod.GET, path=path)
+
+ def exchangeInfo(self):
+
+ """
+ {'timezone': 'UTC', 'serverTime': 1570802268092, 'rateLimits':
+ [{'rateLimitType': 'REQUEST_WEIGHT', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 1200},
+ {'rateLimitType': 'ORDERS', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 1200}],
+ 'exchangeFilters': [], 'symbols':
+ [{'symbol': 'BTCUSDT', 'status': 'TRADING', 'maintMarginPercent': '2.5000', 'requiredMarginPercent': '5.0000',
+ 'baseAsset': 'BTC', 'quoteAsset': 'USDT', 'pricePrecision': 2, 'quantityPrecision': 3, 'baseAssetPrecision': 8,
+ 'quotePrecision': 8,
+ 'filters': [{'minPrice': '0.01', 'maxPrice': '100000', 'filterType': 'PRICE_FILTER', 'tickSize': '0.01'},
+ {'stepSize': '0.001', 'filterType': 'LOT_SIZE', 'maxQty': '1000', 'minQty': '0.001'},
+ {'stepSize': '0.001', 'filterType': 'MARKET_LOT_SIZE', 'maxQty': '1000', 'minQty': '0.001'},
+ {'limit': 200, 'filterType': 'MAX_NUM_ORDERS'},
+ {'multiplierDown': '0.8500', 'multiplierUp': '1.1500', 'multiplierDecimal': '4', 'filterType': 'PERCENT_PRICE'}],
+ 'orderTypes': ['LIMIT', 'MARKET', 'STOP'], 'timeInForce': ['GTC', 'IOC', 'FOK', 'GTX']}]}
+
+ :return:
+ """
+
+ path = '/fapi/v1/exchangeInfo'
+ return self.request(req_method=RequestMethod.GET, path=path)
+
+ def order_book(self, symbol, limit=5):
+ limits = [5, 10, 20, 50, 100, 500, 1000]
+ if limit not in limits:
+ limit = 5
+
+ path = "/fapi/v1/depth"
+ query_dict = {"symbol": symbol,
+ "limit": limit
+ }
+
+ return self.request(RequestMethod.GET, path, query_dict)
+
+ def get_kline(self, symbol, interval: Interval, start_time=None, end_time=None, limit=500, max_try_time=10):
+ """
+
+ :param symbol:
+ :param interval:
+ :param start_time:
+ :param end_time:
+ :param limit:
+ :return:
+ [
+ 1499040000000, // 开盘时间
+ "0.01634790", // 开盘价
+ "0.80000000", // 最高价
+ "0.01575800", // 最低价
+ "0.01577100", // 收盘价(当前K线未结束的即为最新价)
+ "148976.11427815", // 成交量
+ 1499644799999, // 收盘时间
+ "2434.19055334", // 成交额
+ 308, // 成交笔数
+ "1756.87402397", // 主动买入成交量
+ "28.46694368", // 主动买入成交额
+ "17928899.62484339" // 请忽略该参数
+ ]
+ """
+ path = "/fapi/v1/klines"
+
+ query_dict = {
+ "symbol": symbol,
+ "interval": interval.value,
+ "limit": limit
+ }
+
+ if start_time:
+ query_dict['startTime'] = start_time
+
+ if end_time:
+ query_dict['endTime'] = end_time
+
+ for i in range(max_try_time):
+ data = self.request(RequestMethod.GET, path, query_dict)
+ if isinstance(data, list) and len(data):
+ return data
+
+ def get_latest_price(self, symbol):
+ path = "/fapi/v1/ticker/price"
+ query_dict = {"symbol": symbol}
+ return self.request(RequestMethod.GET, path, query_dict)
+
+ def get_ticker(self, symbol):
+ path = "/fapi/v1/ticker/bookTicker"
+ query_dict = {"symbol": symbol}
+ return self.request(RequestMethod.GET, path, query_dict)
+
+ ########################### the following request is for private data ########################
+
+ def _timestamp(self):
+ return int(time.time() * 1000)
+
+ def _sign(self, params):
+
+ requery_string = self.build_parameters(params)
+ hexdigest = hmac.new(self.secret.encode('utf8'), requery_string.encode("utf-8"), hashlib.sha256).hexdigest()
+ return requery_string + '&signature=' + str(hexdigest)
+
+ def get_client_order_id(self):
+
+ """
+ generate the client_order_id for user.
+ :return: new client order id
+ """
+ with self.order_count_lock:
+ self.order_count += 1
+ return "x-cLbi5uMH" + str(self._timestamp()) + str(self.order_count)
+
+ def place_order(self, symbol: str, order_side: OrderSide, order_type: OrderType, quantity, price,
+ time_inforce="GTC", client_order_id=None, recvWindow=5000, stop_price=0):
+
+ """
+ 下单..
+ :param symbol: BTCUSDT
+ :param side: BUY or SELL
+ :param type: LIMIT MARKET STOP
+ :param quantity: 数量.
+ :param price: 价格
+ :param stop_price: 停止单的价格.
+ :param time_inforce:
+ :param params: 其他参数
+
+ LIMIT : timeInForce, quantity, price
+ MARKET : quantity
+ STOP: quantity, price, stopPrice
+ :return:
+
+ """
+
+ path = '/fapi/v1/order'
+
+ if client_order_id is None:
+ client_order_id = self.get_client_order_id()
+
+ params = {
+ "symbol": symbol,
+ "side": order_side.value,
+ "type": order_type.value,
+ "quantity": quantity,
+ "price": price,
+ "recvWindow": recvWindow,
+ "timeInForce": "GTC",
+ "timestamp": self._timestamp(),
+ "newClientOrderId": client_order_id
+ }
+
+ if order_type == OrderType.LIMIT:
+ params['timeInForce'] = time_inforce
+
+ if order_type == OrderType.MARKET:
+ if params.get('price'):
+ del params['price']
+
+ if order_type == OrderType.STOP:
+ if stop_price > 0:
+ params["stopPrice"] = stop_price
+ else:
+ raise ValueError("stopPrice must greater than 0")
+ # print(params)
+ return self.request(RequestMethod.POST, path=path, requery_dict=params, verify=True)
+
+ def get_order(self, symbol, client_order_id=None):
+ path = "/fapi/v1/order"
+ query_dict = {"symbol": symbol, "timestamp": self._timestamp()}
+ if client_order_id:
+ query_dict["origClientOrderId"] = client_order_id
+
+ return self.request(RequestMethod.GET, path, query_dict, verify=True)
+
+ def cancel_order(self, symbol, client_order_id=None):
+ path = "/fapi/v1/order"
+ params = {"symbol": symbol, "timestamp": self._timestamp()}
+ if client_order_id:
+ params["origClientOrderId"] = client_order_id
+
+ return self.request(RequestMethod.DELETE, path, params, verify=True)
+
+ def get_open_orders(self, symbol=None):
+ path = "/fapi/v1/openOrders"
+
+ params = {"timestamp": self._timestamp()}
+ if symbol:
+ params["symbol"] = symbol
+
+ return self.request(RequestMethod.GET, path, params, verify=True)
+
+ def cancel_open_orders(self, symbol):
+ """
+ 撤销某个交易对的所有挂单
+ :param symbol: symbol
+ :return: return a list of orders.
+ """
+ path = "/fapi/v1/allOpenOrders"
+
+ params = {"timestamp": self._timestamp(),
+ "recvWindow": self.recv_window,
+ "symbol": symbol
+ }
+
+ return self.request(RequestMethod.DELETE, path, params, verify=True)
+
+ def get_balance(self):
+ """
+ [{'accountId': 18396, 'asset': 'USDT', 'balance': '530.21334791', 'withdrawAvailable': '530.21334791', 'updateTime': 1570330854015}]
+ :return:
+ """
+ path = "/fapi/v1/balance"
+ params = {"timestamp": self._timestamp()}
+
+ return self.request(RequestMethod.GET, path=path, requery_dict=params, verify=True)
+
+ def get_account_info(self):
+ """
+ {'feeTier': 2, 'canTrade': True, 'canDeposit': True, 'canWithdraw': True, 'updateTime': 0, 'totalInitialMargin': '0.00000000',
+ 'totalMaintMargin': '0.00000000', 'totalWalletBalance': '530.21334791', 'totalUnrealizedProfit': '0.00000000',
+ 'totalMarginBalance': '530.21334791', 'totalPositionInitialMargin': '0.00000000', 'totalOpenOrderInitialMargin': '0.00000000',
+ 'maxWithdrawAmount': '530.2133479100000', 'assets':
+ [{'asset': 'USDT', 'walletBalance': '530.21334791', 'unrealizedProfit': '0.00000000', 'marginBalance': '530.21334791',
+ 'maintMargin': '0.00000000', 'initialMargin': '0.00000000', 'positionInitialMargin': '0.00000000', 'openOrderInitialMargin': '0.00000000',
+ 'maxWithdrawAmount': '530.2133479100000'}]}
+ :return:
+ """
+ path = "/fapi/v1/account"
+ params = {"timestamp": self._timestamp()}
+ return self.request(RequestMethod.GET, path, params, verify=True)
+
+ def get_position_info(self):
+ """
+ [{'symbol': 'BTCUSDT', 'positionAmt': '0.000', 'entryPrice': '0.00000', 'markPrice': '8326.40833498', 'unRealizedProfit': '0.00000000', 'liquidationPrice': '0'}]
+ :return:
+ """
+ path = "/fapi/v1/positionRisk"
+ params = {"timestamp": self._timestamp()}
+ return self.request(RequestMethod.GET, path, params, verify=True)
+
+
+if __name__ == '__main__':
+ # import pandas as pd
+
+ key = "xxxx"
+ secret = 'xxxx'
+ binance = BinanceFutureHttp(api_key=key, secret=secret)
+
+ # import datetime
+ # print(datetime.datetime.now())
+
+ data = binance.get_kline('BTCUSDT', Interval.HOUR_1, limit=100)
+ print(data)
+ print(isinstance(data, list))
+
+ exit()
+ # info = binance.exchangeInfo()
+ # print(info)
+ # exit()
+ # print(binance.order_book(symbol='BTCUSDT', limit=5))
+ # exit()
+
+ # print(binance.latest_price('BTCUSDT'))
+ # kline = binance.kline('BTCUSDT', interval='1m')
+ # print(pd.DataFrame(kline))
+
+ # print(binance.ticker("BTCUSDT"))
+
+ # print(binance.get_ticker('BTCUSDT'))
+ # {'symbol': 'BTCUSDT', 'side': 'SELL', 'type': 'LIMIT', 'quantity': 0.001, 'price': 8360.82, 'recvWindow': 5000, 'timestamp': 1570969995974, 'timeInForce': 'GTC'}
+
+ # data = binance.place_order(symbol="BTCUSDT", side=OrderSide.BUY, order_type=OrderType.MARKET, quantity=0.001, price=8250.82)
+ # print(data)
+
+ # cancel_order = binance.cancel_order("BTCUSDT", order_id="30714952")
+ # print(cancel_order)
+
+ # balance = binance.get_balance()
+ # print(balance)
+
+ # account_info = binance.get_account_info()
+ # print(account_info)
+
+ # account_info = binance.get_position_info()
+ # print(account_info)
+
+ """
+ {'orderId': 30714952, 'symbol': 'BTCUSDT', 'accountId': 18396, 'status': 'NEW', 'clientOrderId': 'ZC3qSbzbODl0GId9idK9hM', 'price': '7900', 'origQty': '0.010', 'executedQty': '0', 'cumQty': '0', 'cumQuote': '0', 'timeInForce': 'GTC', 'type': 'LIMIT', 'reduceOnly': False, 'side': 'BUY', 'stopPrice': '0', 'updateTime': 1569658787083}
+ {'orderId': 30714952, 'symbol': 'BTCUSDT', 'accountId': 18396, 'status': 'NEW', 'clientOrderId': 'ZC3qSbzbODl0GId9idK9hM', 'price': '7900', 'origQty': '0.010', 'executedQty': '0', 'cumQty': '0', 'cumQuote': '0', 'timeInForce': 'GTC', 'type': 'LIMIT', 'reduceOnly': False, 'side': 'BUY', 'stopPrice': '0', 'updateTime': 1569658787083}
+ """
diff --git a/binance/binance_future_trader.py b/binance/binance_future_trader.py
new file mode 100644
index 0000000..f50f002
--- /dev/null
+++ b/binance/binance_future_trader.py
@@ -0,0 +1,226 @@
+from binance import BinanceFutureHttp, OrderStatus, OrderType, OrderSide
+from utils import config
+from utils import round_to
+import logging
+from datetime import datetime
+
+class BinanceFutureTrader(object):
+
+ def __init__(self):
+ self.http_client = BinanceFutureHttp(api_key=config.api_key, secret=config.api_secret, proxy_host=config.proxy_host, proxy_port=config.proxy_port)
+
+ self.buy_orders = [] # 买单. buy orders
+ self.sell_orders = [] # 卖单. sell orders
+
+
+ def get_bid_ask_price(self):
+
+ ticker = self.http_client.get_ticker(config.symbol)
+
+ bid_price = 0
+ ask_price = 0
+ if ticker:
+ bid_price = float(ticker.get('bidPrice', 0))
+ ask_price = float(ticker.get('askPrice', 0))
+
+ return bid_price, ask_price
+
+ def get_latest_price(self):
+ #获取最新价格
+ ticker = self.http_client.get_latest_price(config.symbol)
+ price = 0
+ if ticker:
+ price = float(ticker.get('price', 0))
+ return price
+
+ def grid_trader(self):
+ """
+ 执行核心逻辑,网格交易的逻辑.
+
+ the grid trading logic
+ :return:
+ """
+
+ bid_price, ask_price = self.get_bid_ask_price()
+ print(f"bid_price: {bid_price}, ask_price: {ask_price}, time: {datetime.now()}")
+
+ quantity = round_to(float(config.quantity), float(config.min_qty))
+
+ self.buy_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
+ self.sell_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
+
+ buy_delete_orders = [] # 需要删除买单
+ sell_delete_orders = [] # 需要删除的卖单
+
+
+ # 买单逻辑,检查成交的情况.
+ for buy_order in self.buy_orders:
+
+ check_order = self.http_client.get_order(buy_order.get('symbol', config.symbol),client_order_id=buy_order.get('clientOrderId'))
+
+ if check_order:
+ if check_order.get('status') == OrderStatus.CANCELED.value:
+ buy_delete_orders.append(buy_order)
+ print(f"buy order status was canceled: {check_order.get('status')}, time: {datetime.now()}")
+ elif check_order.get('status') == OrderStatus.FILLED.value:
+ # 买单成交,挂卖单.
+ print(f"买单成交了, 时间: {datetime.now()}")
+ logging.info(f"买单成交时间: {datetime.now()}, 价格: {check_order.get('price')}, 数量: {check_order.get('origQty')}")
+
+ sell_price = round_to(float(check_order.get("price")) * (1 + float(config.gap_percent)), float(config.min_price))
+
+ if 0 < sell_price < ask_price:
+ # 防止价格
+ sell_price = round_to(ask_price, float(config.min_price))
+
+ new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL, order_type=OrderType.LIMIT, quantity=quantity, price=sell_price)
+ if new_sell_order:
+ print(f"买单成交,下了对应价格的卖单: {new_sell_order}, 时间: {datetime.now()}")
+ buy_delete_orders.append(buy_order)
+ self.sell_orders.append(new_sell_order)
+
+ buy_price = round_to(float(check_order.get("price")) * (1 - float(config.gap_percent)),
+ config.min_price)
+
+ if buy_price > bid_price > 0:
+ buy_price = round_to(buy_price, float(config.min_price))
+
+ new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY, order_type=OrderType.LIMIT, quantity=quantity, price=buy_price)
+ if new_buy_order:
+ print(f"买单成交,下了更低价的买单: {new_buy_order}, 时间: {datetime.now()}")
+ self.buy_orders.append(new_buy_order)
+
+
+ elif check_order.get('status') == OrderStatus.NEW.value:
+ print(f"buy order status is: New , 时间: {datetime.now()}")
+ else:
+ print(f"buy order status is not above options: {check_order.get('status')}, 时间: {datetime.now()}")
+
+ # 过期或者拒绝的订单删除掉.
+ for delete_order in buy_delete_orders:
+ self.buy_orders.remove(delete_order)
+
+ # 卖单逻辑, 检查卖单成交情况.
+ for sell_order in self.sell_orders:
+
+ check_order = self.http_client.get_order(sell_order.get('symbol', config.symbol),
+ client_order_id=sell_order.get('clientOrderId'))
+ if check_order:
+ if check_order.get('status') == OrderStatus.CANCELED.value:
+ sell_delete_orders.append(sell_order)
+
+ print(f"sell order status was canceled: {check_order.get('status')}, 时间: {datetime.now()}")
+ elif check_order.get('status') == OrderStatus.FILLED.value:
+ print(f"卖单成交了, 时间: {datetime.now()}")
+ logging.info(
+ f"卖单成交时间: {datetime.now()}, 价格: {check_order.get('price')}, 数量: {check_order.get('origQty')}")
+ # 卖单成交,先下买单.
+ buy_price = round_to(float(check_order.get("price")) * (1 - float(config.gap_percent)), float(config.min_price))
+ if buy_price > bid_price > 0:
+ buy_price = round_to(buy_price, float(config.min_price))
+
+ new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY,
+ order_type=OrderType.LIMIT, quantity=quantity, price=buy_price)
+ if new_buy_order:
+ print(f"卖单成交,下了对应价格的买单: {new_buy_order}, 时间: {datetime.now()}")
+ sell_delete_orders.append(sell_order)
+ self.buy_orders.append(new_buy_order)
+
+ sell_price = round_to(float(check_order.get("price")) * (1 + float(config.gap_percent)), float(config.min_price))
+
+ if 0 < sell_price < ask_price:
+ # 防止价格
+ sell_price = round_to(ask_price, float(config.min_price))
+
+ new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
+ order_type=OrderType.LIMIT, quantity=quantity,
+ price=sell_price)
+ if new_sell_order:
+ print(f"卖单成交,下了更高价的卖单: {new_sell_order}, 时间: {datetime.now()}")
+ self.sell_orders.append(new_sell_order)
+
+ elif check_order.get('status') == OrderStatus.NEW.value:
+ print(f"sell order status is: New, 时间: {datetime.now()}")
+ else:
+ print(f"sell order status is not in above options: {check_order.get('status')}, 时间: {datetime.now()}")
+
+ # 过期或者拒绝的订单删除掉.
+ for delete_order in sell_delete_orders:
+ self.sell_orders.remove(delete_order)
+
+ # 没有买单的时候.
+ if len(self.buy_orders) <= 0:
+ if bid_price > 0:
+ price = round_to(bid_price * (1 - float(config.gap_percent)), float(config.min_price))
+
+ buy_order = self.http_client.place_order(symbol=config.symbol,order_side=OrderSide.BUY, order_type=OrderType.LIMIT, quantity=quantity,price=price)
+ print(f'没有买单,根据盘口下买单: {buy_order}, 时间: {datetime.now()}')
+ if buy_order:
+ self.buy_orders.append(buy_order)
+ else:
+ self.buy_orders.sort(key=lambda x: float(x['price']), reverse=False) # 最低价到最高价
+ delete_orders = []
+ for i in range(len(self.buy_orders) -1):
+ order = self.buy_orders[i]
+ next_order = self.buy_orders[i+1]
+
+ if float(next_order['price'])/float(order['price']) - 1 < 0.001:
+ print(f"买单之间价差太小,撤销订单:{next_order}, 时间: {datetime.now()}")
+ cancel_order = self.http_client.cancel_order(next_order.get('symbol'),
+ client_order_id=next_order.get('clientOrderId'))
+ if cancel_order:
+ delete_orders.append(next_order)
+
+ for order in delete_orders:
+ self.buy_orders.remove(order)
+
+
+ if len(self.buy_orders) > int(config.max_orders): # 最多允许的挂单数量.
+ # 订单数量比较多的时候.
+ self.buy_orders.sort(key=lambda x: float(x['price']), reverse=False) # 最低价到最高价
+
+ delete_order = self.buy_orders[0]
+ print(f"订单太多了,撤销最低价的买单:{delete_order}, 时间: {datetime.now()}")
+ order = self.http_client.cancel_order(delete_order.get('symbol'), client_order_id=delete_order.get('clientOrderId'))
+ if order:
+ self.buy_orders.remove(delete_order)
+
+ # 没有卖单的时候.
+ if len(self.sell_orders) <= 0:
+ if ask_price > 0:
+ price = round_to(ask_price * (1 + float(config.gap_percent)), float(config.min_price))
+ sell_order = self.http_client.place_order(symbol=config.symbol,order_side=OrderSide.SELL, order_type=OrderType.LIMIT, quantity=quantity,price=price)
+ print(f'没有卖单,根据盘口下卖单:{sell_order} , 时间: {datetime.now()}')
+ if sell_order:
+ self.sell_orders.append(sell_order)
+
+ else:
+ self.sell_orders.sort(key=lambda x: float(x['price']), reverse=False) # 最低价到最高价
+ delete_orders = []
+ for i in range(len(self.sell_orders) - 1):
+ order = self.sell_orders[i]
+ next_order = self.sell_orders[i + 1]
+
+ if float(next_order['price']) / float(order['price']) - 1 < 0.001:
+ print(f"卖单之间价差太小,撤销订单:{next_order}, 时间: {datetime.now()}")
+ cancel_order = self.http_client.cancel_order(next_order.get('symbol'),
+ client_order_id=next_order.get('clientOrderId'))
+ if cancel_order:
+ delete_orders.append(next_order)
+
+ for order in delete_orders:
+ self.sell_orders.remove(order)
+
+ if len(self.sell_orders) > int(config.max_orders): # 最多允许的挂单数量.
+ # 订单数量比较多的时候.
+ self.sell_orders.sort(key=lambda x: x['price'], reverse=True) # 最高价到最低价
+
+ delete_order = self.sell_orders[0]
+ print(f"订单太多了,撤销最高价的卖单:{delete_order}, 时间:{datetime.now()}")
+ order = self.http_client.cancel_order(delete_order.get('symbol'),
+ client_order_id=delete_order.get('clientOrderId'))
+ if order:
+ self.sell_orders.remove(delete_order)
+
+
+
diff --git a/binance/binance_spot.py b/binance/binance_spot.py
new file mode 100644
index 0000000..88febc9
--- /dev/null
+++ b/binance/binance_spot.py
@@ -0,0 +1,456 @@
+from binance import OrderType, OrderStatus, OrderSide, RequestMethod,Interval
+import requests
+import time
+import hmac
+import hashlib
+from threading import Lock
+from utils import config
+from utils import utility
+
+
+class BinanceSpotHttp(object):
+ '''
+ # https://binance-docs.github.io/apidocs/spot/cn/ # 152d3db758
+ # 如果上面的baseURL访问有性能问题,请访问下面的API集群:
+ # https://api1.binance.com
+ # https://api2.binance.com
+ # https://api3.binance.com
+ # https://api4.binance.com
+ # ORDERS rateLimits 100次/10s 200000次/1day
+ '''
+
+ def __init__(self, api_key=None, secret=None, host=None, proxy_host=None, proxy_port=0, timeout=5, try_counts=5):
+ self.api_key = api_key
+ self.secret = secret
+ self.host = host if host else "https://api.binance.com"
+ self.recv_window = 10000
+ self.timeout = timeout
+ self.order_count_lock = Lock()
+ self.order_count = 1_000_000
+ self.try_counts = try_counts # 失败尝试的次数.
+ self.proxy_host = proxy_host
+ self.proxy_port = proxy_port
+
+ @property
+ def proxies(self):
+ if self.proxy_host and self.proxy_port:
+ proxy = f"http://{self.proxy_host}:{self.proxy_port}"
+ return {"http": proxy, "https": proxy}
+
+ return None
+
+ def build_parameters(self, params: dict):
+ keys = list(params.keys())
+ keys.sort()
+ return '&'.join([f"{key}={params[key]}" for key in params.keys()])
+
+ def request(self, req_method: RequestMethod, path: str, requery_dict=None, verify=False):
+ url = self.host + path
+
+ if verify:
+ query_str = self._sign(requery_dict)
+ url += '?' + query_str
+ elif requery_dict:
+ url += '?' + self.build_parameters(requery_dict)
+ headers = {"X-MBX-APIKEY": self.api_key}
+
+ for i in range(0, self.try_counts):
+ try:
+ response = requests.request(req_method.value, url=url, headers=headers, timeout=self.timeout, proxies=self.proxies)
+ http_code = response.status_code
+
+ if http_code == 200:
+ return response.json()
+ elif http_code == 400 and "Account has insufficient balance for requested action." in str(response.json()):
+ print(f"交易对: {config.symbol} 余额不足")
+ break
+ elif http_code == 400 and "Filter failure: MIN_NOTIONAL" in str(response.json()):
+ print(f"交易对: {config.symbol} 最小下单数量不够,多买点")
+ break
+ elif http_code == 400 and "Unknown order sent." in str(response.json()):
+ print(f"交易对: {config.symbol} 订单号错误")
+ print(f"请求结果{str(response.json())}")
+ break
+ elif http_code == 400 and "Illegal characters found in parameter 'symbol'" in str(response.json()):
+ print(f"交易对: {config.symbol} 交易对配置错误,无法识别")
+ break
+ elif http_code == 400 and "This action disabled is on this account" in str(response.json()):
+ print(f"交易对: {config.symbol} 账号无权此操作")
+ break
+ else:
+ print("未知请求错误:")
+ print(response.json(), http_code)
+
+ except Exception as error:
+ print(f"请求:{path}, 发生了错误: {error}")
+ time.sleep(3)
+
+ def get_ping(self):
+ #测试服务器连通性
+ #测试能否联通 Rest API。
+ path = '/api/v3/ping'
+ return self.request(req_method=RequestMethod.GET, path=path)
+
+ def get_server_time(self):
+ #获取服务器时间
+ #测试能否联通 Rest API 并 获取服务器时间。
+ path = '/api/v3/time'
+ return self.request(req_method=RequestMethod.GET, path=path)
+
+
+
+
+ def get_exchange_info(self):
+ #交易规范信息
+ #获取交易规则和交易对信息。
+
+ """
+ return:
+ the exchange info in json format:
+ {'timezone': 'UTC', 'serverTime': 1570802268092, 'rateLimits':
+ [{'rateLimitType': 'REQUEST_WEIGHT', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 1200},
+ {'rateLimitType': 'ORDERS', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 1200}],
+ 'exchangeFilters': [], 'symbols':
+ [{'symbol': 'BTCUSDT', 'status': 'TRADING', 'maintMarginPercent': '2.5000', 'requiredMarginPercent': '5.0000',
+ 'baseAsset': 'BTC', 'quoteAsset': 'USDT', 'pricePrecision': 2, 'quantityPrecision': 3, 'baseAssetPrecision': 8,
+ 'quotePrecision': 8,
+ 'filters': [{'minPrice': '0.01', 'maxPrice': '100000', 'filterType': 'PRICE_FILTER', 'tickSize': '0.01'},
+ {'stepSize': '0.001', 'filterType': 'LOT_SIZE', 'maxQty': '1000', 'minQty': '0.001'},
+ {'stepSize': '0.001', 'filterType': 'MARKET_LOT_SIZE', 'maxQty': '1000', 'minQty': '0.001'},
+ {'limit': 200, 'filterType': 'MAX_NUM_ORDERS'},
+ {'multiplierDown': '0.8500', 'multiplierUp': '1.1500', 'multiplierDecimal': '4', 'filterType': 'PERCENT_PRICE'}],
+ 'orderTypes': ['LIMIT', 'MARKET', 'STOP'], 'timeInForce': ['GTC', 'IOC', 'FOK', 'GTX']}]}
+
+ """
+
+ path = '/api/v3/exchangeInfo'
+ return self.request(req_method=RequestMethod.GET, path=path)
+
+
+
+ def get_order_book(self, symbol, limit=5):
+ """
+ 深度信息
+ https://binance-docs.github.io/apidocs/spot/cn/#e7746f7d60
+ :param symbol: BTCUSDT, BNBUSDT ect, 交易对.
+ :param limit: market depth. 默认 100; 最大 5000. 可选值:[5, 10, 20, 50, 100, 500, 1000, 5000]
+ :return: return order_book in json 返回订单簿,json数据格式.
+ """
+ limits = [5, 10, 20, 50, 100, 500, 1000]
+ if limit not in limits:
+ limit = 5
+
+ path = "/api/v3/depth"
+ query_dict = {"symbol": symbol,
+ "limit": limit
+ }
+
+ return self.request(RequestMethod.GET, path, query_dict)
+
+ def get_recent_trades(self, symbol, limit=5):
+ """
+ 近期成交列表
+ https://binance-docs.github.io/apidocs/spot/cn/#38a975b802
+ :param symbol: BTCUSDT, BNBUSDT ect, 交易对.
+ :param limit: 默认 500; 最大值 1000.
+ :return: return order_book in json 返回订单簿,json数据格式.
+ """
+
+ if limit >= 1000:
+ limit = 1000
+
+ path = "/api/v3/trades"
+ query_dict = {"symbol": symbol,
+ "limit": limit
+ }
+
+ return self.request(RequestMethod.GET, path, query_dict)
+
+ def get_kline(self, symbol, interval: Interval, start_time=None, end_time=None, limit=500, max_try_time=10):
+ """
+ 获取K线数据.
+ 每根K线代表一个交易对。
+ 每根K线的开盘时间可视为唯一ID
+ https://binance-docs.github.io/apidocs/spot/cn/#c59e471e81
+ :param symbol:
+ :param interval: 间隔
+ :param start_time:
+ :param end_time:
+ :param limit: 默认 500; 最大 1000
+ :param max_try_time:
+ :return:
+ [
+ [
+ 1499040000000, // 开盘时间
+ "0.01634790", // 开盘价
+ "0.80000000", // 最高价
+ "0.01575800", // 最低价
+ "0.01577100", // 收盘价(当前K线未结束的即为最新价)
+ "148976.11427815", // 成交量
+ 1499644799999, // 收盘时间
+ "2434.19055334", // 成交额
+ 308, // 成交笔数
+ "1756.87402397", // 主动买入成交量
+ "28.46694368", // 主动买入成交额
+ "17928899.62484339" // 请忽略该参数
+ ]
+]
+ """
+ path = "/api/v3/klines"
+ query_dict = {
+ "symbol": symbol,
+ "interval": interval,
+ "limit": limit
+ }
+
+ # query_dict = {
+ # "symbol": symbol,
+ # "interval": interval.value,
+ # "limit": limit
+ # }
+
+ if start_time:
+ query_dict['startTime'] = start_time
+
+ if end_time:
+ query_dict['endTime'] = end_time
+
+ for i in range(max_try_time):
+ data = self.request(RequestMethod.GET, path, query_dict)
+ if isinstance(data, list) and len(data):
+ return data
+
+ def get_latest_price(self, symbol):
+ """
+ 获取交易对最新价格
+ 不发送交易对参数,则会返回所有交易对信息
+ 权重:
+ 1 单一交易对;
+ 2 交易对参数缺失
+ :param symbol: 获取最新的价格.
+ :return: {'symbol': 'BTCUSDT', 'price': '9168.90000000'}
+
+
+ """
+ path = "/api/v3/ticker/price"
+ query_dict = {"symbol": symbol}
+ return self.request(RequestMethod.GET, path, query_dict)
+
+ def get_avg_price_5min(self, symbol):
+ """
+ 当前平均价格 in last 5min
+ 权重: 1
+ :param symbol:
+ :return:
+ {
+ "mins": 5,
+ "price": "9.35751834"
+ }
+
+ """
+ path = "/api/v3/avgPrice"
+ query_dict = {"symbol": symbol}
+ return self.request(RequestMethod.GET, path, query_dict)
+
+ def get_price_info_24h(self, symbol):
+ """
+ 24hr 价格变动情况
+ 24 小时滚动窗口价格变动数据。 请注意,不携带symbol参数会返回全部交易对数据,不仅数据庞大,而且权重极高
+ 权重: 1 单一交易对;
+ 40 交易对参数缺失;
+ 请注意,不携带symbol参数会返回全部交易对数据
+
+ :param symbol:
+ :return:
+{
+ "symbol": "BNBBTC",
+ "priceChange": "-94.99999800",
+ "priceChangePercent": "-95.960",
+ "weightedAvgPrice": "0.29628482",
+ "prevClosePrice": "0.10002000",
+ "lastPrice": "4.00000200",
+ "lastQty": "200.00000000",
+ "bidPrice": "4.00000000",
+ "askPrice": "4.00000200",
+ "openPrice": "99.00000000",
+ "highPrice": "100.00000000",
+ "lowPrice": "0.10000000",
+ "volume": "8913.30000000",
+ "quoteVolume": "15.30000000",
+ "openTime": 1499783499040,
+ "closeTime": 1499869899040,
+ "firstId": 28385, // 首笔成交id
+ "lastId": 28460, // 末笔成交id
+ "count": 76 // 成交笔数
+}
+
+ """
+ path = "/api/v3/ticker/24hr"
+ query_dict = {"symbol": symbol}
+ return self.request(RequestMethod.GET, path, query_dict)
+
+ def get_ticker(self, symbol):
+ """
+ 当前最优挂单
+ 返回当前最优的挂单(最高买单,最低卖单)
+ bid price的本意是出价 最高买价
+ ask price的本意是要价 最低卖价
+ ask是“要”的意思,就卖家喊出来的价
+ bid是“投标”的意思,是买家愿意出的最高价。
+ :param symbol: 交易对
+ :return: 返回的数据如下:
+ {
+ 'symbol': 'BTCUSDT', 'bidPrice': '9168.50000000', 'bidQty': '1.27689900',
+ 'askPrice': '9168.51000000', 'askQty': '0.93307800'
+ }
+ """
+ path = "/api/v3/ticker/bookTicker"
+ query_dict = {"symbol": symbol}
+ return self.request(RequestMethod.GET, path, query_dict)
+
+ def get_client_order_id(self):
+ """
+ generate the client_order_id for user.
+ :return:
+ """
+ with self.order_count_lock:
+ self.order_count += 1
+ return config.symbol + str(utility.get_current_timestamp()) + str(self.order_count)
+
+ def _sign(self, params):
+ """
+ 签名的方法, signature for the private request.
+ :param params: request parameters
+ :return:
+ """
+
+ query_string = self.build_parameters(params)
+ hex_digest = hmac.new(self.secret.encode('utf8'), query_string.encode("utf-8"), hashlib.sha256).hexdigest()
+ return query_string + '&signature=' + str(hex_digest)
+
+ def place_order(self, symbol: str, order_side: OrderSide, order_type: OrderType, quantity: float, price: float,
+ client_order_id: str = None, time_inforce="GTC", stop_price=0):
+ """
+
+ :param symbol: 交易对名称
+ :param order_side: 买或者卖, BUY or SELL
+ :param order_type: 订单类型 LIMIT or other order type.
+ :param quantity: 数量
+ :param price: 价格.
+ :param client_order_id: 用户的订单ID
+ :param time_inforce:
+ :param stop_price:
+ :return:
+ """
+
+ path = '/api/v3/order'
+
+ if client_order_id is None:
+ client_order_id = self.get_client_order_id()
+
+
+
+ params = {
+ "symbol": symbol,
+ "side": order_side.value,
+ "type": order_type.value,
+ "quantity": quantity,
+ "price": price,
+ "recvWindow": self.recv_window,
+ "timestamp": utility.get_current_timestamp(),
+ "newClientOrderId": client_order_id
+ }
+
+
+ if order_type == OrderType.LIMIT:
+ params['timeInForce'] = time_inforce
+
+ if order_type == OrderType.MARKET:
+ if params.get('price'):
+ del params['price']
+
+ if order_type == OrderType.STOP:
+ if stop_price > 0:
+ params["stopPrice"] = stop_price
+ else:
+ raise ValueError("stopPrice must greater than 0")
+
+ return self.request(RequestMethod.POST, path=path, requery_dict=params, verify=True)
+
+ def get_order(self, symbol: str, client_order_id: str):
+ """
+ 获取订单状态.
+ :param symbol:
+ :param client_order_id:
+ :return:
+ """
+ path = "/api/v3/order"
+ prams = {"symbol": symbol, "timestamp": utility.get_current_timestamp(), "origClientOrderId": client_order_id}
+
+ return self.request(RequestMethod.GET, path, prams, verify=True)
+
+ def cancel_order(self, symbol, client_order_id):
+ """
+ 撤销订单.
+ :param symbol:
+ :param client_order_id:
+ :return:
+ """
+ path = "/api/v3/order"
+ params = {"symbol": symbol, "timestamp": utility.get_current_timestamp(),
+ "origClientOrderId": client_order_id
+ }
+
+ for i in range(0, 3):
+ try:
+ order = self.request(RequestMethod.DELETE, path, params, verify=True)
+ return order
+ except Exception as error:
+ print(f'取消订单失败:{error}')
+ return
+
+ def get_open_orders(self, symbol=None):
+ """
+ 获取所有的订单.
+ :param symbol: BNBUSDT, or BTCUSDT etc.
+ :return:
+ """
+ path = "/api/v3/openOrders"
+
+ params = {"timestamp": utility.get_current_timestamp()}
+ if symbol:
+ params["symbol"] = symbol
+
+ return self.request(RequestMethod.GET, path, params, verify=True)
+
+ def cancel_open_orders(self, symbol):
+ """
+ 撤销某个交易对的所有挂单
+ :param symbol: symbol
+ :return: return a list of orders.
+ """
+ path = "/api/v3/openOrders"
+
+ params = {"timestamp": utility.get_current_timestamp(),
+ "recvWindow": self.recv_window,
+ "symbol": symbol
+ }
+
+ return self.request(RequestMethod.DELETE, path, params, verify=True)
+
+ def get_account_info(self):
+ """
+ {'feeTier': 2, 'canTrade': True, 'canDeposit': True, 'canWithdraw': True, 'updateTime': 0, 'totalInitialMargin': '0.00000000',
+ 'totalMaintMargin': '0.00000000', 'totalWalletBalance': '530.21334791', 'totalUnrealizedProfit': '0.00000000',
+ 'totalMarginBalance': '530.21334791', 'totalPositionInitialMargin': '0.00000000', 'totalOpenOrderInitialMargin': '0.00000000',
+ 'maxWithdrawAmount': '530.2133479100000', 'assets':
+ [{'asset': 'USDT', 'walletBalance': '530.21334791', 'unrealizedProfit': '0.00000000', 'marginBalance': '530.21334791',
+ 'maintMargin': '0.00000000', 'initialMargin': '0.00000000', 'positionInitialMargin': '0.00000000', 'openOrderInitialMargin': '0.00000000',
+ 'maxWithdrawAmount': '530.2133479100000'}]}
+ :return:
+ """
+ path = "/api/v3/account"
+ params = {"timestamp": utility.get_current_timestamp(),
+ "recvWindow": self.recv_window
+ }
+ return self.request(RequestMethod.GET, path, params, verify=True)
diff --git a/binance/binance_trader.py b/binance/binance_trader.py
new file mode 100644
index 0000000..009ed8f
--- /dev/null
+++ b/binance/binance_trader.py
@@ -0,0 +1,434 @@
+from binance import BinanceSpotHttp, OrderStatus, OrderType, OrderSide
+from utils import config
+from utils import round_to
+from utils import utility
+
+
+class BinanceTrader(object):
+
+ def __init__(self):
+ """
+ :param api_key:
+ :param secret:
+ :param trade_type: 交易的类型, only support future and spot.
+ """
+ self.loop_counts = 0
+ self.config_error_counts = 0 #止损价配置不当,提示次数
+ self.sleep_time = config.sleep_time #循环间隔秒数
+ self.cancel_time = config.cancel_time #取消订单周期
+ self.http_client = BinanceSpotHttp(api_key=config.api_key, secret=config.api_secret, proxy_host=config.proxy_host, proxy_port=config.proxy_port)
+
+ self.buy_orders = [] # 本地买单列表.
+ self.sell_orders = [] # 本地卖单列表.
+ self.deficit_scroll_map = {} # 滚动止盈的清仓价
+
+
+ def get_avg_price_5min(self):
+ #获取5分钟内的平均价
+ ticker = self.http_client.get_avg_price_5min(config.symbol)
+ price = 0
+ if ticker:
+ price = float(ticker.get('price', 0))
+ return price
+
+ def get_latest_price(self):
+ #获取最新价格
+ ticker = self.http_client.get_latest_price(config.symbol)
+ price = 0
+ if ticker:
+ price = float(ticker.get('price', 0))
+ return price
+
+ def get_price_change_percent_24h(self):
+ #获取24h内的价格变化百分比数据
+ ticker = self.http_client.get_price_info_24h(config.symbol)
+ priceChangePercent = 0
+ if ticker:
+ priceChangePercent = float(ticker.get('priceChangePercent', 0))
+ return priceChangePercent
+
+ def get_bid_ask_price(self):
+ #最高买价 最低卖价
+ ticker = self.http_client.get_ticker(config.symbol)
+
+ bid_price = 0
+ ask_price = 0
+ if ticker:
+ bid_price = float(ticker.get('bidPrice', 0))
+ ask_price = float(ticker.get('askPrice', 0))
+
+ return bid_price, ask_price
+
+ def get_depth(self,limit):
+ ticker = self.http_client.get_order_book(config.symbol,limit=limit)
+ if ticker:
+ #high_price = float(ticker[0][2])
+ print(ticker)
+ return 123
+
+
+ def get_kline(self,interval):
+ ticker = self.http_client.get_kline(config.symbol,interval=interval,limit=1)
+ if ticker:
+ high_price = float(ticker[0][2])
+ low_price = float(ticker[0][3])
+ return low_price, high_price
+
+ # 获取倒数第二个k线数据
+ def get_kline_pre4(self,interval):
+ ticker = self.http_client.get_kline(config.symbol,interval=interval,limit=4)
+ if ticker:
+ high_price = float(ticker[3][2])
+ low_price = float(ticker[3][3])
+ return low_price, high_price
+
+ def create_buy_order(self,quantity,buy_price):
+ new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY,
+ order_type=OrderType.LIMIT, quantity=quantity,
+ price=buy_price)
+ if new_buy_order:
+ # 买单维护到买单列表待处理
+ self.buy_orders.append(new_buy_order)
+ print(f"买单创建 价格: {buy_price}, 数量: {quantity} ")
+ else:
+ print(f"买单创建失败 价格: {buy_price}, 数量: {quantity} ")
+
+ def create_sell_order(self,quantity,sell_price):
+ new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
+ order_type=OrderType.LIMIT, quantity=quantity, price=sell_price)
+ if new_sell_order:
+ # 放到卖单列表待处理
+ self.sell_orders.append(new_sell_order)
+ print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ")
+ else:
+ print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ")
+
+ def create_sell_order_by_client_id(self,quantity,sell_price,client_order_id):
+ new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
+ order_type=OrderType.LIMIT, quantity=quantity, price=sell_price,client_order_id=client_order_id)
+ if new_sell_order is not None:
+ # 放到卖单列表待处理
+ self.sell_orders.append(new_sell_order)
+ print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ")
+ return True
+ else:
+ print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ")
+ return False
+
+ def create_sell_order_market(self,quantity):
+ new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
+ order_type=OrderType.MARKET, quantity=quantity)
+ if new_sell_order:
+ # 市价订单必定成功
+ self.sell_orders.append(new_sell_order)
+ print(f"交易对:{config.symbol} 市价卖出数量: {quantity} ")
+ return True
+ else:
+ print(f"交易对:{config.symbol} 卖单创建失败 市价卖出数量: {quantity} ")
+ return False
+
+ def cancel_single_order(self,cancel_order):
+ order = self.http_client.cancel_order(config.symbol,cancel_order.get('clientOrderId'))
+ if order is None:
+ utility.alert(f"订单撤销失败 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ")
+ return False
+ else:
+ print(f"订单撤销成功 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ")
+ return True
+
+
+ def cancel_open_orders(self):
+ open_orders_list = self.http_client.get_open_orders(config.symbol)
+ for open_order in open_orders_list:
+ if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.BUY.value:
+ #只取消本客户端创建的买单
+ if open_order.get('clientOrderId') and config.symbol in open_order.get('clientOrderId'):
+ self.cancel_single_order(open_order)
+ print(f"买单{open_order.get('clientOrderId')}已取消取消")
+
+ def sync_open_orders(self):
+ open_orders_list = self.http_client.get_open_orders(config.symbol)
+ for open_order in open_orders_list:
+ #只同步本客户端创建的订单
+ if open_order.get('clientOrderId') and config.symbol in open_order.get('clientOrderId'):
+ if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.BUY.value:
+ self.buy_orders.append(open_order)
+ print(f"买单{open_order.get('clientOrderId')}同步到本地")
+ if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.SELL.value:
+ self.sell_orders.append(open_order)
+ print(f"卖单{open_order.get('clientOrderId')}同步到本地")
+
+ #网格交易核心逻辑.
+ def grid_trader(self):
+ """
+ #网格交易核心逻辑.
+ """
+
+ quantity = round_to(float(config.quantity), float(config.min_qty)) ## quantity是config.quantity到config.min_qty的精度转换
+ profit_scroll = float(config.profit_scroll) ## 每次刷新止盈价的比例
+ deficit_scroll = float(config.deficit_scroll) ## 每次刷新止损价的比例
+ profit_intend = float(config.profit_intend) ## 每次准备刷新止盈价的比例,到了这个比例直接刷
+ gap_percent= float(config.gap_percent) ## 卖单提价比例
+
+ self.loop_counts+=1
+ print(f"{utility.cn_time()} 第{self.loop_counts}轮循环开始")
+
+ bid_price, ask_price = self.get_bid_ask_price()
+ print(f"{config.symbol}:最高买价bid_price: {bid_price}, 最低卖价ask_price: {ask_price}")
+ avg_price_5min = float(self.get_avg_price_5min())
+ #latest_price = self.get_latest_price()
+
+ #5分钟k线 15分钟k线
+ low_price_in_15m, high_price_in_15m = self.get_kline("15m")
+ print(f"{config.symbol}:15分钟最低价: {low_price_in_15m}, 15分钟最高价: {high_price_in_15m}")
+
+ low_price_in_4h, high_price_in_4h = self.get_kline("4h")
+ low_price_pre_in_4h, high_price_pre_in_4h = self.get_kline_pre4("2h")
+ print(f"low_price_in_4h: {low_price_in_4h}")
+ print(f"high_price_in_4h: {high_price_in_4h}")
+ print(f"low_price_pre_in_4h: {low_price_pre_in_4h}")
+ print(f"high_price_pre_in_4h: {high_price_pre_in_4h}")
+ # 取波峰波谷的中间值
+ peak_price = high_price_in_4h if high_price_in_4h <= high_price_pre_in_4h else high_price_pre_in_4h
+ bottom_price = low_price_in_4h if low_price_in_4h >= low_price_pre_in_4h else low_price_pre_in_4h
+ delta_price_in_4h = float(peak_price)-float(bottom_price)
+ price_stop_to_sell = float(bottom_price) + delta_price_in_4h * 0.1
+ price_stop_to_buy = float(peak_price) - delta_price_in_4h * 0.8
+ print(f"high_price_in_4h_4h: {peak_price}")
+ print(f"low_price_in_4h_4h: {bottom_price}")
+ print(f"价格上限: {price_stop_to_buy}")
+ print(f"价格下限: {price_stop_to_sell}")
+ # price_stop_to_sell = float(config.price_stop_to_sell)
+ # price_stop_to_buy = float(config.price_stop_to_buy)
+
+
+
+ self.buy_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
+ self.sell_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
+
+
+ buy_delete_orders = [] # 需要删除的买单
+ sell_delete_orders = [] # 需要删除的卖单
+
+
+
+ # 买单逻辑,检查买单列表成交的情况.一旦成功立即加价卖
+ print("-------------买单逻辑-----------------")
+ for buy_order in self.buy_orders:
+ check_order = self.http_client.get_order(buy_order.get('symbol', config.symbol),client_order_id=buy_order.get('clientOrderId'))
+ if check_order:
+ order_status = check_order.get('status')
+ order_price = check_order.get('price')
+ order_orig_qty = check_order.get('origQty')
+ order_client_id = buy_order.get('clientOrderId')
+
+ #取消状态的买单 不管
+ if order_status == OrderStatus.CANCELED.value:
+ buy_delete_orders.append(buy_order)
+ print(f"买单{order_client_id}状态为取消: {order_status}")
+
+ #成交状态买单,需要处理
+ elif order_status == OrderStatus.FILLED.value:
+ print(f"成交状态的买单: {order_client_id} 成交时间: {utility.cn_time()} 价格: {order_price} 数量: {order_orig_qty}")
+ # 买单成交后,提高价格,挂盈利卖单
+ sell_price = round_to(float(order_price) * (1 + float(config.gap_percent)), float(config.min_price))
+ if 0 < sell_price < ask_price:
+ # 防止价格小于最低卖价ask_price
+ sell_price = round_to(ask_price, float(config.min_price))
+ #如果卖价小于设定的持仓价格price_stop_to_sell,将卖价提高至持仓价,才交易
+ if 0 < sell_price < price_stop_to_sell:
+ print(f"卖价{sell_price} 小于持仓价{price_stop_to_sell} ,已调整为持仓价交易")
+ sell_price = price_stop_to_sell
+ #盈利卖单挂
+ if self.create_sell_order(quantity, sell_price):
+ print(f"{utility.cn_time()} :交易对:{config.symbol}, 买单 {order_client_id} 成交, 价格: {order_price}, 数量: {order_orig_qty}")
+ # 盈利卖单挂成功的话,删掉本买单
+ buy_delete_orders.append(buy_order)
+ if buy_order in self.buy_orders:
+ self.buy_orders.remove(buy_order)
+
+
+
+ #未成交的买单不处理
+ elif order_status == OrderStatus.NEW.value:
+ print(f"未成交的买单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+
+ # 部分成交的买单 提示下就行了
+ elif order_status == OrderStatus.PARTIALLY_FILLED.value:
+ print(f"部分成交的买单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+
+ #异常状态买单
+ else:
+ utility.alert(f"交易对:{config.symbol}, 时间: {utility.cn_time()}, 买单{order_client_id}失败{order_status}")
+
+ # 过期或者拒绝的订单删除掉.
+ for delete_order in buy_delete_orders:
+ if delete_order in self.buy_orders:
+ self.buy_orders.remove(delete_order)
+
+
+ # 卖单逻辑, 检查卖单成交情况
+ print("--------------卖单逻辑----------------")
+ for sell_order in self.sell_orders:
+ check_order = self.http_client.get_order(sell_order.get('symbol', config.symbol),client_order_id=sell_order.get('clientOrderId'))
+ if check_order:
+ order_status = check_order.get('status')
+ order_price = check_order.get('price')
+ order_orig_qty = check_order.get('origQty')
+ order_client_id = sell_order.get('clientOrderId')
+ #卖单状态为取消 不管
+ if order_status == OrderStatus.CANCELED.value:
+ sell_delete_orders.append(sell_order)
+ print(f"卖单{order_client_id}状态为取消: {order_status}")
+
+ #卖单状态为成交
+ elif order_status == OrderStatus.FILLED.value:
+ print(f"卖单{order_client_id}成交时间: {utility.cn_time()}, 价格: {order_price}, 数量: {order_orig_qty}")
+ #第一遍才发通知
+ if sell_order not in sell_delete_orders:
+ utility.alert(f"卖单成交: {utility.cn_time()} {order_client_id}, 交易对:{config.symbol}, 价格: {order_price}, 数量: {order_orig_qty}")
+ # 卖单成交,不再维护该卖单状态
+ sell_delete_orders.append(sell_order)
+ if sell_order in self.sell_orders:
+ self.sell_orders.remove(sell_order)
+
+
+ # 新挂的卖单 创建移动止盈策略
+ elif order_status == OrderStatus.NEW.value:
+ print(f"还没成交的卖单:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+ print(f"当前最低卖价: {ask_price}")
+ orig_buy_price = float(order_price) / (float(gap_percent) + 1)
+ print(f"预估本单的买入价格: {orig_buy_price}")
+ triger_price = float(order_price) * float(profit_intend)
+ print(f"移动止盈触发价格: {triger_price}")
+ if ask_price >= triger_price:
+ print("最低卖价大于移动止盈触发价格,先删除本卖单,再创建一个更高价的卖单")
+ if self.cancel_single_order(check_order):
+ # 删除成功 再创建一个更高价的卖单
+ new_order_price_profit = float(order_price) * float(profit_scroll)
+ new_order_price_deficit = float(ask_price) * float(deficit_scroll)
+ new_order_price_profit = round_to(new_order_price_profit, float(config.min_price))
+ new_order_price_deficit = round_to(new_order_price_deficit, float(config.min_price))
+ print(f"new_order_price_profit: {new_order_price_profit}")
+ print(f"new_order_price_deficit: {new_order_price_deficit}")
+ profit_client_order_id = self.http_client.get_client_order_id()
+ profit_sell_order = self.create_sell_order_by_client_id(order_orig_qty,
+ new_order_price_profit,
+ profit_client_order_id)
+ if profit_sell_order:
+ print("----------------移动止盈触发成功-------yyyyyyyyyyyyyyyyyyyyyyyyyyyy------")
+ print(
+ f"{utility.cn_time()} :卖单 {order_client_id}滚动止盈触发新卖单{profit_client_order_id},交易对:{config.symbol},新期望价格: {new_order_price_profit}, 数量: {order_orig_qty}")
+ # 移动止盈卖单挂成功的话,本地不再维护原卖单
+ sell_delete_orders.append(sell_order)
+ if sell_order in self.sell_orders:
+ self.sell_orders.remove(sell_order)
+ # 本地记录新卖单的止损价格
+ self.deficit_scroll_map[profit_client_order_id] = new_order_price_deficit
+ else:
+ print("----------------移动止盈触发失败------eeeeeeeeeeeeeeeeeeeeeeeeeeee-------")
+ print(
+ f"{utility.cn_time()} 移动止盈卖单创建失败 交易对:{config.symbol} 价格: {new_order_price_profit}, 数量: {order_orig_qty} ")
+ utility.alert(
+ f"{utility.cn_time()} 移动止盈卖单创建失败 交易对:{config.symbol} 价格: {new_order_price_profit}, 数量: {order_orig_qty} ")
+ else:
+ print("原买单删除失败")
+
+ # 当前卖单存在止损价,且最低卖价不大于止损价时候,止损处理掉当前卖单
+ # 其实所存的止损价是经过滚动止盈产生的,所以还是在盈利
+ # 当前卖价要大于买单价格才可以
+ elif order_client_id in self.deficit_scroll_map and ask_price <= self.deficit_scroll_map[order_client_id] and ask_price > orig_buy_price:
+ # 先删除本卖单,挂太高了,卖不出去
+ if self.cancel_open_orders(check_order):
+ # 市价卖出本订单待卖的币
+ self.create_sell_order_market(order_orig_qty)
+ print("----------移动止损成功--------------")
+ else:
+ print(f"止损卖单取消失败:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+
+
+
+ # 部分成交的卖单 提示下就行了
+ elif order_status == OrderStatus.PARTIALLY_FILLED.value:
+ print(f"部分成交的卖单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+
+ else:
+ utility.alert(f"挂卖单失败 交易对:{config.symbol}, 时间: {utility.cn_time()}, {order_status}")
+
+ #处理过期或者拒绝的订单,不在维护到本地
+ for delete_order in sell_delete_orders:
+ if delete_order in self.sell_orders:
+ self.sell_orders.remove(delete_order)
+
+ # 买单数量未满 并且卖单也没满时候 usdt没有积压 可以新建买单
+ if len(self.buy_orders) < int(config.max_orders) and len(self.sell_orders) < int(config.max_sell_orders):
+ print("买单数量未满,卖单也没积压,开始创建一个新买单:")
+ print("------------------------------")
+ if bid_price > 0:
+ buy_price = round_to(bid_price * (1 - float(config.gap_percent)), float(config.min_price))
+ ##如果买价大于设定的抛仓价格price_stop_to_buy,将买价降低至抛仓价,才交易
+ if buy_price > price_stop_to_buy > 0:
+ buy_price = price_stop_to_buy
+ #动态价格保护,如果买价不高于15分钟k线最高值,说明价格在跌,适合买
+ if buy_price <= high_price_in_15m :
+ # 如果价格不大于5分钟内的平均价 说明价格还可以,能继续买入
+ if buy_price <= avg_price_5min:
+ buy_price = round_to(buy_price,float(config.min_price))
+ print(f"开始创建买单:价格{buy_price} 数量 {quantity} ")
+ self.create_buy_order(quantity,buy_price)
+ else:
+ print(f"买价 {buy_price}大于平均价 {avg_price_5min} 再等等")
+ else:
+ print(f"买价 {buy_price}大于15分钟最高价 {high_price_in_15m} 高位勿买")
+
+ # 买单数量过多,cancel_time 取消一次价格最离谱的买单
+ elif len(self.buy_orders) >= int(config.max_orders):
+ # cancel_time更新一次 主循环cancel_time/gcd_time次
+ cancel_period=self.cancel_time/self.sleep_time
+ print(f"当前买单数量达到{config.max_orders},将在{(cancel_period - self.loop_counts % cancel_period)*self.sleep_time}秒后删除一个价格最离谱的买单")
+ if self.loop_counts % cancel_period == 0:
+ print(f"开始删除价格最离谱的买单:")
+ print("------------------------------")
+ # 最离谱到最接近
+ self.buy_orders.sort(key=lambda x: abs(float(x['price'])-float(avg_price_5min)), reverse=True)
+ impossible_order=self.buy_orders[0]
+ if self.cancel_single_order(impossible_order):
+ if impossible_order in self.buy_orders:
+ self.buy_orders.remove(impossible_order)
+ buy_delete_orders.append(impossible_order)
+ print(f"买单列表已满 价格离谱的买单{impossible_order.get('clientOrderId')}删除 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ")
+ else:
+ print(f"买单列表已满 价格离谱的买单{impossible_order.get('clientOrderId')}删除失败 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ")
+ for fade_order in self.buy_orders:
+ if float(fade_order.get('price')) > high_price_in_15m or float(fade_order.get('price')) < low_price_in_15m:
+ if fade_order in self.buy_orders:
+ self.buy_orders.remove(fade_order)
+ buy_delete_orders.append(fade_order)
+ print(f"取消价格未在15m k线的买单{fade_order.get('clientOrderId')} 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ")
+
+
+
+ # 没有卖单的时候 暂时先不创建卖单,防止利润计算错误
+ if len(self.sell_orders) <= 0:
+ print(f"当前没有卖单,请注意查看{config.symbol}余额")
+ print("------------------------------")
+
+
+
+ #卖单过多,暂不处理
+ elif len(self.sell_orders) > int(config.max_orders):
+ print("卖单过多:")
+ print("------------------------------")
+ print(f"交易对{config.symbol}卖单较多,大于个{config.max_orders} 请处理")
+
+ #集中处理 buy_delete_orders sell_delete_orders
+ for buy_order in buy_delete_orders:
+ if self.cancel_single_order(buy_order):
+ if buy_order in buy_delete_orders:
+ buy_delete_orders.remove(buy_order)
+ for sell_order in sell_delete_orders:
+ if self.cancel_single_order(sell_order):
+ if sell_order in sell_delete_orders:
+ sell_delete_orders.remove(sell_order)
+
+ print(f"{utility.cn_time()} 第{self.loop_counts}轮循环结束 休息{self.sleep_time}s")
\ No newline at end of file
diff --git a/binance/trade.txt b/binance/trade.txt
new file mode 100644
index 0000000..de30dda
--- /dev/null
+++ b/binance/trade.txt
@@ -0,0 +1,12 @@
+
+ #循环提醒配置不当
+ ##循环配置不当的逻辑先去掉,直接从4h kline自适应
+ # if avg_price_5min > price_stop_to_buy or avg_price_5min < price_stop_to_sell:
+ # print(f"交易对{config.symbol}:止损范围配置不当,恐难以成交,五分钟内平均价: {avg_price_5min}")
+ # self.config_error_counts+=1
+ # #15次循环提醒一次配置不当
+ # if self.config_error_counts%15 == 0:
+ # self.config_error_counts = 0
+ # utility.alert(f"交易对{config.symbol}:止损范围配置不当,恐难以成交,五分钟内平均价: {avg_price_5min}")
+ # else:
+ # self.config_error_counts = 0
diff --git a/binance/trader_bak b/binance/trader_bak
new file mode 100644
index 0000000..22e5613
--- /dev/null
+++ b/binance/trader_bak
@@ -0,0 +1,404 @@
+from binance import BinanceSpotHttp, OrderStatus, OrderType, OrderSide
+from utils import config
+from utils import round_to
+from utils import utility
+
+
+class BinanceTrader(object):
+
+ def __init__(self):
+ """
+ :param api_key:
+ :param secret:
+ :param trade_type: 交易的类型, only support future and spot.
+ """
+ self.loop_counts = 0
+ self.config_error_counts = 0 #止损价配置不当,提示次数
+ self.http_client = BinanceSpotHttp(api_key=config.api_key, secret=config.api_secret, proxy_host=config.proxy_host, proxy_port=config.proxy_port)
+
+ self.buy_orders = [] # 本地买单列表.
+ self.sell_orders = [] # 本地卖单列表.
+
+
+
+
+ def get_avg_price_5min(self):
+ #获取5分钟内的平均价
+ ticker = self.http_client.get_avg_price_5min(config.symbol)
+ price = 0
+ if ticker:
+ price = float(ticker.get('price', 0))
+ return price
+
+ def get_latest_price(self):
+ #获取最新价格
+ ticker = self.http_client.get_latest_price(config.symbol)
+ price = 0
+ if ticker:
+ price = float(ticker.get('price', 0))
+ return price
+
+ def get_price_change_percent_24h(self):
+ #获取24h内的价格变化百分比数据
+ ticker = self.http_client.get_price_info_24h(config.symbol)
+ priceChangePercent = 0
+ if ticker:
+ priceChangePercent = float(ticker.get('priceChangePercent', 0))
+ return priceChangePercent
+
+ def get_bid_ask_price(self):
+ #最高买价 最低卖价
+ ticker = self.http_client.get_ticker(config.symbol)
+
+ bid_price = 0
+ ask_price = 0
+ if ticker:
+ bid_price = float(ticker.get('bidPrice', 0))
+ ask_price = float(ticker.get('askPrice', 0))
+
+ return bid_price, ask_price
+
+ def get_depth(self,limit):
+ ticker = self.http_client.get_order_book(config.symbol,limit=limit)
+ if ticker:
+ #high_price = float(ticker[0][2])
+ print(ticker)
+ return 123
+
+ def get_kline_15m(self):
+ ticker = self.http_client.get_kline(config.symbol,interval="15m",limit=1)
+ if ticker:
+ high_price = float(ticker[0][2])
+ low_price = float(ticker[0][3])
+ return low_price, high_price
+
+ def get_kline_5m(self):
+ ticker = self.http_client.get_kline(config.symbol,interval="5m",limit=1)
+ if ticker:
+ high_price = float(ticker[0][2])
+ low_price = float(ticker[0][3])
+ return low_price, high_price
+
+ def create_buy_order(self,quantity,buy_price):
+ new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY,
+ order_type=OrderType.LIMIT, quantity=quantity,
+ price=buy_price)
+ if new_buy_order:
+ # 买单维护到买单列表待处理
+ self.buy_orders.append(new_buy_order)
+ print(f"买单创建 价格: {buy_price}, 数量: {quantity} ")
+ else:
+ print(f"买单创建失败 价格: {buy_price}, 数量: {quantity} ")
+
+ def create_buy_order_by_client_id(self,quantity,buy_price,client_order_id):
+ new_buy_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.BUY,
+ order_type=OrderType.LIMIT, quantity=quantity,
+ price=buy_price,client_order_id=client_order_id)
+ if new_buy_order:
+ # 买单维护到买单列表待处理
+ self.buy_orders.append(new_buy_order)
+ print(f"买单创建 价格: {buy_price}, 数量: {quantity} ")
+ else:
+ print(f"买单创建失败 价格: {buy_price}, 数量: {quantity} ")
+
+ def create_sell_order(self,quantity,sell_price):
+ new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
+ order_type=OrderType.LIMIT, quantity=quantity, price=sell_price)
+ if new_sell_order:
+ # 放到卖单列表待处理
+ self.sell_orders.append(new_sell_order)
+ print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ")
+ else:
+ print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ")
+
+ def create_sell_order_by_client_id(self,quantity,sell_price,client_order_id):
+ new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
+ order_type=OrderType.LIMIT, quantity=quantity, price=sell_price,client_order_id=client_order_id)
+ if new_sell_order:
+ # 放到卖单列表待处理
+ self.sell_orders.append(new_sell_order)
+ print(f"卖单创建 价格: {sell_price}, 数量: {quantity} ")
+ else:
+ print(f"卖单创建失败 价格: {sell_price}, 数量: {quantity} ")
+
+ def create_sell_order_market(self,quantity):
+ new_sell_order = self.http_client.place_order(symbol=config.symbol, order_side=OrderSide.SELL,
+ order_type=OrderType.MARKET, quantity=quantity)
+ if new_sell_order:
+ # 市价订单必定成功
+ self.sell_orders.append(new_sell_order)
+ print(f"交易对:{config.symbol} 市价卖出数量: {quantity} ")
+ else:
+ print(f"交易对:{config.symbol} 卖单创建失败 市价卖出数量: {quantity} ")
+
+ def cancel_single_order(self,cancel_order):
+ order = self.http_client.cancel_order(config.symbol,cancel_order.get('clientOrderId'))
+ if order:
+ print(f"订单撤销 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ")
+ else:
+ print(f"订单撤销失败 symbol: {config.symbol}, clientOrderId: {cancel_order.get('clientOrderId')} ")
+
+ def cancel_open_orders(self):
+ open_orders_list = self.http_client.get_open_orders(config.symbol)
+ for open_order in open_orders_list:
+ if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.BUY.value:
+ #只取消本客户端创建的买单
+ if open_order.get('clientOrderId') and config.symbol in open_order.get('clientOrderId'):
+ self.cancel_single_order(open_order)
+ print(f"买单{open_order.get('clientOrderId')}已取消取消")
+
+ def sync_open_orders(self):
+ open_orders_list = self.http_client.get_open_orders(config.symbol)
+ for open_order in open_orders_list:
+ #只同步本客户端创建的订单
+ if open_order.get('clientOrderId') and config.symbol in open_order.get('clientOrderId'):
+ if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.BUY.value:
+ self.buy_orders.append(open_order)
+ print(f"买单{open_order.get('clientOrderId')}同步到本地")
+ if open_order.get('status') == OrderStatus.NEW.value and open_order.get('side') == OrderSide.SELL.value:
+ self.sell_orders.append(open_order)
+ print(f"卖单{open_order.get('clientOrderId')}同步到本地")
+
+ #网格交易核心逻辑.
+ def grid_trader(self):
+ """
+ #网格交易核心逻辑.
+ """
+ price_stop_to_sell = float(config.price_stop_to_sell)
+ price_stop_to_buy = float(config.price_stop_to_buy)
+ quantity = round_to(float(config.quantity), float(config.min_qty)) ## quantity是config.quantity到config.min_qty的四舍五入值
+ profit_scroll = float(config.profit_scroll) ## 每次刷新止盈价的比例
+ deficit_scroll = float(config.deficit_scroll) ## 每次刷新止损价的比例
+ profit_intend = float(config.profit_intend) ## 每次准备刷新止盈价的比例,到了这个比例直接刷
+
+ self.loop_counts+=1
+ print(f"{utility.cn_time()} 第{self.loop_counts}轮循环开始")
+
+ bid_price, ask_price = self.get_bid_ask_price()
+ print(f"{config.symbol}:最高买价bid_price: {bid_price}, 最低卖价ask_price: {ask_price}")
+ avg_price_5min = float(self.get_avg_price_5min())
+ #latest_price = self.get_latest_price()
+
+ #5分钟k线 15分钟k线
+ low_price_in_15m, high_price_in_15m = self.get_kline_15m()
+ print(f"{config.symbol}:15分钟最低价: {low_price_in_15m}, 15分钟最高价: {high_price_in_15m}")
+
+ # low_price_in_5m, high_price_in_5m = self.get_kline_5m()
+ # print(f"{config.symbol}:5分钟最低价: {low_price_in_5m}, 5分钟最高价: {high_price_in_5m}")
+
+ #循环提醒配置不当
+ if avg_price_5min > price_stop_to_buy or avg_price_5min < price_stop_to_sell:
+ print(f"交易对{config.symbol}:止损范围配置不当,恐难以成交,五分钟内平均价: {avg_price_5min}")
+ self.config_error_counts+=1
+ #15次循环提醒一次配置不当
+ if self.config_error_counts%15 == 0:
+ self.config_error_counts = 0
+ utility.alert(f"交易对{config.symbol}:止损范围配置不当,恐难以成交,五分钟内平均价: {avg_price_5min}")
+ else:
+ self.config_error_counts = 0
+
+
+ self.buy_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
+ self.sell_orders.sort(key=lambda x: float(x['price']), reverse=True) # 最高价到最低价.
+
+
+ buy_delete_orders = [] # 需要删除的买单
+ sell_delete_orders = [] # 需要删除的卖单
+ deficit_scroll_map = {} # 滚动止盈的清仓价
+ buy_order_price_map = {} # 买单的价格
+ buy_order_sell_map = {} # 买卖单对应关系
+
+
+ # 买单逻辑,检查买单列表成交的情况.一旦成功立即加价卖
+ # print("当前委托买单:")
+ # print(self.buy_orders)
+ print("-------------买单逻辑-----------------")
+ for buy_order in self.buy_orders:
+ check_order = self.http_client.get_order(buy_order.get('symbol', config.symbol),client_order_id=buy_order.get('clientOrderId'))
+ if check_order:
+ order_status = check_order.get('status')
+ order_price = check_order.get('price')
+ order_orig_qty = check_order.get('origQty')
+ order_client_id = buy_order.get('clientOrderId')
+
+ #取消状态的买单 不管
+ if order_status == OrderStatus.CANCELED.value:
+ buy_delete_orders.append(buy_order)
+ print(f"买单{order_client_id}状态为取消: {order_status}")
+
+ #成交状态买单,需要处理
+ elif order_status == OrderStatus.FILLED.value:
+ print(f"买单{order_client_id}成交时间: {utility.cn_time()}, 价格: {order_price}, 数量: {order_orig_qty}")
+ # 买单成交后,提高价格,挂盈利卖单
+ sell_price = round_to(float(order_price) * (1 + float(config.gap_percent)), float(config.min_price))
+ if 0 < sell_price < ask_price:
+ # 防止价格小于最低卖价ask_price
+ sell_price = round_to(ask_price, float(config.min_price))
+ #如果卖价小于设定的持仓价格price_stop_to_sell,将卖价提高至持仓价,才交易
+ if 0 < sell_price < price_stop_to_sell:
+ print(f"卖价{sell_price} 小于持仓价{price_stop_to_sell} ,已调整为持仓价交易")
+ sell_price = price_stop_to_sell
+ #盈利卖单挂
+ profit_client_order_id = BinanceSpotHttp.get_client_order_id()
+ if self.create_sell_order_by_client_id(quantity, sell_price,profit_client_order_id):
+ print(f"{utility.cn_time()} :交易对:{config.symbol}, 买单 {order_client_id} 成交, 价格: {order_price}, 数量: {order_orig_qty}")
+ # 盈利卖单挂成功的话,删掉本买单
+ buy_delete_orders.append(buy_order)
+ self.buy_orders.remove(buy_order)
+ # 维护买卖单关系
+ buy_order_sell_map[order_client_id] = profit_client_order_id
+
+
+
+ #未成交的买单不处理
+ elif order_status == OrderStatus.NEW.value:
+ print(f"未成交的买单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+
+ # 部分成交的买单 提示下就行了
+ elif order_status == OrderStatus.PARTIALLY_FILLED.value:
+ print(f"部分成交的买单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+
+ #异常状态买单
+ else:
+ utility.alert(f"交易对:{config.symbol}, 时间: {utility.cn_time()}, 买单{order_client_id}失败{order_status}")
+
+ # 过期或者拒绝的订单删除掉.
+ for delete_order in buy_delete_orders:
+ self.buy_orders.remove(delete_order)
+
+
+ # 卖单逻辑, 检查卖单成交情况.不做措施
+ # print("当前委托卖单:")
+ # print(self.sell_orders)
+ print("--------------卖单逻辑----------------")
+ for sell_order in self.sell_orders:
+ check_order = self.http_client.get_order(sell_order.get('symbol', config.symbol),client_order_id=sell_order.get('clientOrderId'))
+ if check_order:
+ order_status = check_order.get('status')
+ order_price = check_order.get('price')
+ order_orig_qty = check_order.get('origQty')
+ order_client_id = sell_order.get('clientOrderId')
+ #卖单状态为取消 不管
+ if order_status == OrderStatus.CANCELED.value:
+ sell_delete_orders.append(sell_order)
+ print(f"卖单{order_client_id}状态为取消: {order_status}")
+
+ #卖单状态为成交
+ elif order_status == OrderStatus.FILLED.value:
+ print(f"卖单{order_client_id}成交时间: {utility.cn_time()}, 价格: {order_price}, 数量: {order_orig_qty}")
+ #第一遍才发通知
+ if sell_order not in sell_delete_orders:
+ utility.alert(f"卖单成交: {utility.cn_time()} {order_client_id}, 交易对:{config.symbol}, 价格: {order_price}, 数量: {order_orig_qty}")
+ # 卖单成交,不再维护该卖单状态
+ sell_delete_orders.append(sell_order)
+ self.sell_orders.remove(sell_order)
+
+ # 新挂的卖单 创建移动止盈策略
+ elif order_status == OrderStatus.NEW.value:
+ print(f"还没成交的卖单:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+ print(f"当前最低卖价: {ask_price}")
+ #预估
+ # 最低卖价大于原卖单定价的止盈比例时候,先删除本卖单,再创建一个更高价的卖单
+ if ask_price >= order_price * profit_intend:
+ # 先删除本卖单
+ if self.cancel_open_orders(check_order):
+ # 再创建一个更高价的卖单
+ new_order_price_profit = order_price * profit_scroll
+ new_order_price_deficit = ask_price * deficit_scroll
+ profit_client_order_id = BinanceSpotHttp.get_client_order_id()
+ profit_sell_order = self.self.create_sell_order_by_client_id(order_orig_qty,new_order_price_profit,profit_client_order_id)
+ if profit_sell_order:
+ print(
+ f"{utility.cn_time()} :卖单 {order_client_id}滚动止盈触发新卖单{profit_client_order_id},交易对:{config.symbol},新期望价格: {new_order_price_profit}, 数量: {order_orig_qty}")
+ # 移动止盈卖单挂成功的话,本地不再维护原卖单
+ sell_delete_orders.append(sell_order)
+ self.sell_orders.remove(sell_order)
+ # 本地记录新卖单的止损价格
+ deficit_scroll_map[profit_client_order_id] = new_order_price_deficit
+ else:
+ print(f"{utility.cn_time()} 移动止盈卖单创建失败 交易对:{config.symbol} 价格: {new_order_price_profit}, 数量: {order_orig_qty} ")
+ utility.alert(f"{utility.cn_time()} 移动止盈卖单创建失败 交易对:{config.symbol} 价格: {new_order_price_profit}, 数量: {order_orig_qty} ")
+ else:
+ print(f"止盈卖单取消失败:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+ # 当前卖单存在止损价,且最低卖价不大于止损价时候,止损处理掉当前卖单
+ # 其实所存的止损价是经过滚动止盈产生的,所以还是在盈利
+ elif deficit_scroll_map.has_key(order_client_id) and ask_price <= deficit_scroll_map[order_client_id]:
+ # 先删除本卖单,挂太高了,卖不出去
+ if self.cancel_open_orders(check_order):
+ # 市价卖出本订单待卖的币
+ self.create_sell_order_market(order_orig_qty)
+ else:
+ print(f"止损卖单取消失败:{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+
+
+
+ # 部分成交的卖单 提示下就行了
+ elif order_status == OrderStatus.PARTIALLY_FILLED.value:
+ print(f"部分成交的卖单{order_client_id} 价格: {order_price}, 数量: {order_orig_qty}")
+
+ else:
+ utility.alert(f"挂卖单失败 交易对:{config.symbol}, 时间: {utility.cn_time()}, {order_status}")
+
+ # 过期或者拒绝的订单删除掉.
+ for delete_order in sell_delete_orders:
+ self.sell_orders.remove(delete_order)
+
+ # 买单数量未满 并且卖单也没满时候 usdt没有积压 可以新建买单
+ if len(self.buy_orders) < int(config.max_orders) and len(self.sell_orders) < int(config.max_sell_orders):
+ print("买单数量未满,卖单也没积压,开始创建一个新买单:")
+ print("------------------------------")
+ if bid_price > 0:
+ buy_price = round_to(bid_price * (1 - float(config.gap_percent)), float(config.min_price))
+ ##如果买价大于设定的抛仓价格price_stop_to_buy,将买价降低至抛仓价,才交易
+ if buy_price > price_stop_to_buy > 0:
+ buy_price = price_stop_to_buy
+ #动态价格保护,如果买价不高于15分钟k线最高值,说明价格在跌,适合买
+ if buy_price <= high_price_in_15m :
+ # 如果价格不大于5分钟内的平均价 说明价格还可以,能继续买入
+ if buy_price <= avg_price_5min:
+ print(f"开始创建买单:价格{buy_price} 数量 {quantity} ")
+ buy_client_order_id = BinanceSpotHttp.get_client_order_id()
+ if self.create_buy_order_by_client_id(quantity,buy_price,buy_client_order_id):
+ # 买入成功后记录买单的原价
+ buy_order_price_map[buy_client_order_id] = buy_price
+ else:
+ print(f"买单{buy_client_order_id}创建失败 数量 {quantity} 价格{buy_price}")
+ else:
+ print(f"买价 {buy_price}大于平均价 {avg_price_5min} 再等等")
+ else:
+ print(f"买价 {buy_price}大于15分钟最高价 {high_price_in_15m} 高位勿买")
+
+ # 买单数量过多,2min取消一次价格最离谱的买单
+ elif len(self.buy_orders) >= int(config.max_orders):
+ # 主循环6次 2min更新一次
+ print(f"当前买单数量达到{config.max_orders},将在{(6 - self.loop_counts % 6)*20}秒后删除一个价格最离谱的买单")
+ if self.loop_counts % 6 == 0:
+ print(f"开始删除价格最离谱的买单:")
+ print("------------------------------")
+ # 最离谱到最接近
+ self.buy_orders.sort(key=lambda x: abs(float(x['price'])-float(avg_price_5min)), reverse=True)
+ impossible_order=self.buy_orders[0]
+ if self.cancel_single_order(impossible_order):
+ self.buy_orders.remove(impossible_order)
+ print(f"买单列表已满 价格离谱的买单{impossible_order.get('clientOrderId')}删除 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ")
+ for fade_order in self.buy_orders:
+ if float(fade_order.get('price')) > high_price_in_15m or float(fade_order.get('price')) < low_price_in_15m:
+ self.buy_orders.remove(fade_order)
+ print(f"取消价格未在15m k线的买单{fade_order.get('clientOrderId')} 价格: {impossible_order.get('price')}, 数量: {impossible_order.get('origQty')} ")
+
+
+
+ # 没有卖单的时候 暂时先不创建卖单,防止利润计算错误
+ if len(self.sell_orders) <= 0:
+ print(f"当前没有卖单,请注意查看{config.symbol}余额")
+ print("------------------------------")
+
+
+
+ #卖单过多,暂不处理
+ elif len(self.sell_orders) > int(config.max_orders):
+ print("卖单过多:")
+ print("------------------------------")
+ print(f"交易对{config.symbol}卖单较多,大于个{config.max_orders} 请处理")
+
+ print(f"{utility.cn_time()} 第{self.loop_counts}轮循环结束 休息20s")
\ No newline at end of file
diff --git a/conf/config-example.json b/conf/config-example.json
new file mode 100644
index 0000000..c9fa5a3
--- /dev/null
+++ b/conf/config-example.json
@@ -0,0 +1,28 @@
+ {
+ "sleep_time": 10,
+ "cancel_time": 120,
+ "platform": "binance_spot",
+ "symbol": "SHIBUSDT",
+ "api_key": "44444444444444444444444444",
+ "api_secret": "4444444444444444444444444444444444444444444444444444",
+ "profit_scroll": 1.005,
+ "profit_intend": 0.996,
+ "deficit_scroll": 0.985,
+ "gap_percent": 0.01,
+ "quantity": 500000,
+ "min_price": 0.00000001,
+ "price_stop_to_buy": 0.7,
+ "price_stop_to_sell": 0.5,
+ "min_qty": 100000,
+ "max_orders": 2,
+ "max_sell_orders": 2,
+ "proxy_host": "privoxy",
+ "proxy_port": 8118,
+ "dingding_robot_url": "https://oapi.dingtalk.com/robot/send?access_token=666666666666666666666666666666666d29c",
+ "dingding_user_phone": "1111111111",
+ "user_email": "me@me.me",
+ "SMTP_HOST": "smtp.me.me",
+ "SMTP_PORT": 80,
+ "SMTP_USER": "me2@me.me",
+ "SMTP_PASSWORD": "77777777777777777777777777777777777"
+ }
diff --git a/conf_huobi/config-example.json b/conf_huobi/config-example.json
new file mode 100644
index 0000000..402d747
--- /dev/null
+++ b/conf_huobi/config-example.json
@@ -0,0 +1,11 @@
+{
+ "account_id": 44444,
+ "api_key": "e7f555555555555555555b3",
+ "api_secret": "f065555555555555555555555555555aec",
+ "symbol_spot": ["btcusdt","btc3lusdt","eth3susdt"],
+ "symbol_margin": ["linkusdt","xmrusdt","bsvusdt","ethusdt"],
+ "symbol_c2c": ["linkusdt","xmrusdt","bsvusdt","ethusdt"],
+ "proxy_host": "172.16.0.137",
+ "proxy_port": 58591
+}
+
diff --git a/docker_build.md b/docker_build.md
new file mode 100644
index 0000000..bccc852
--- /dev/null
+++ b/docker_build.md
@@ -0,0 +1,26 @@
+# prod 机器上
+
+## docker build push ,k8s update img
+
+```bash
+
+CURRENT_VERSION=41
+CURRENT_IMG="me/grid_trader"
+cd /root
+rm -rf grid_trader
+git clone https://mmmm/grid_trader.git
+cd grid_trader
+docker build -t $CURRENT_IMG:$CURRENT_VERSION .
+docker push $CURRENT_IMG:$CURRENT_VERSION
+clear
+echo $CURRENT_VERSION
+
+
+DEPLOYMENTS=`kubectl -n sre get deployment |grep binance-trader-qy |awk '{print $1}' |xargs`
+for deployment in $DEPLOYMENTS;do
+ kubectl set image deployments $deployment *=$CURRENT_IMG:$CURRENT_VERSION -n sre
+done
+
+```
+
+
diff --git a/example/__init__.py b/example/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/example/account/get_account_asset_valuation.py b/example/account/get_account_asset_valuation.py
new file mode 100644
index 0000000..56e5484
--- /dev/null
+++ b/example/account/get_account_asset_valuation.py
@@ -0,0 +1,24 @@
+from huobi.client.account import AccountClient
+from example.api_key import *
+
+account_client = AccountClient(api_key=g_api_key,secret_key=g_secret_key)
+
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#bd9157656f
+spot:现货账户,
+margin:逐仓杠杆账户,
+otc:OTC 账户,
+point:点卡账户,
+super-margin:全仓杠杆账户,
+investment: C2C杠杆借出账户,
+borrow: C2C杠杆借入账户,
+矿池账户: minepool,
+ETF账户: etf,
+抵押借贷账户: crypto-loans
+
+逐仓/全仓/C2C杠杆账户(margin/super-margin/borrow)会在第一次划转资产时创建,如果未划转过资产则不会有杠杆账户。
+'''
+
+account_type = "etf" #币币账户余额
+asset_valuation = account_client.get_account_asset_valuation(account_type=account_type, valuation_currency="usd")
+asset_valuation.print_object()
diff --git a/example/account/get_account_balance.py b/example/account/get_account_balance.py
new file mode 100644
index 0000000..92b730b
--- /dev/null
+++ b/example/account/get_account_balance.py
@@ -0,0 +1,3522 @@
+from huobi.client.account import AccountClient
+from huobi.utils import LogInfo
+from example.api_key import *
+
+
+# 获取账户总余额-明细
+
+'''
+ssh://root@40.83.77.152:22/usr/local/bin/python3 -u /opt/binance_grid_trader/example/account/get_account_balance.py
+====== (SDK encapsulated api) not recommend for low performance and frequence limitation ======
+Account ID : 18788142
+Account Type : margin
+Account State : working
+Subtype : btcusdt
+
+ Currency : btc
+ Balance Type : trade
+ Balance : 0.000000593380222235
+
+ Currency : btc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : btc
+ Balance Type : loan
+ Balance : 0
+
+ Currency : btc
+ Balance Type : interest
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 0.000000000000011349
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0.000000000000000001
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 18766866
+Account Type : margin
+Account State : working
+Subtype : bchusdt
+
+ Currency : bch
+ Balance Type : trade
+ Balance : 0.000066417266187046
+
+ Currency : bch
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bch
+ Balance Type : loan
+ Balance : 0
+
+ Currency : bch
+ Balance Type : interest
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 27.726710382000002202
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0.000000000000000001
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 18688813
+Account Type : margin
+Account State : working
+Subtype : linkusdt
+
+ Currency : link
+ Balance Type : trade
+ Balance : 0.000872717632331562
+
+ Currency : link
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : link
+ Balance Type : loan
+ Balance : -926.06600784
+
+ Currency : link
+ Balance Type : interest
+ Balance : -1.41368408
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 12255.3867979586747305
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 18600.000000000000000004
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 18716338
+Account Type : margin
+Account State : working
+Subtype : omgusdt
+
+ Currency : omg
+ Balance Type : trade
+ Balance : 1.95822488
+
+ Currency : omg
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : omg
+ Balance Type : loan
+ Balance : 0
+
+ Currency : omg
+ Balance Type : interest
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 0.00000000748
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 9736507
+Account Type : spot
+Account State : working
+Subtype :
+
+ Currency : lun
+ Balance Type : trade
+ Balance : 0
+
+ Currency : lun
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ksm
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ksm
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ring
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ring
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bsv3l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bsv3l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : fil
+ Balance Type : trade
+ Balance : 0
+
+ Currency : fil
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bag
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bag
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : kcash
+ Balance Type : trade
+ Balance : 0
+
+ Currency : kcash
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bal
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bal
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : theta
+ Balance Type : trade
+ Balance : 0
+
+ Currency : theta
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : npxs
+ Balance Type : trade
+ Balance : 0
+
+ Currency : npxs
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ssp
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ssp
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : fis
+ Balance Type : trade
+ Balance : 0
+
+ Currency : fis
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : trio
+ Balance Type : trade
+ Balance : 0
+
+ Currency : trio
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : egt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : egt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : stpt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : stpt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bat
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bat
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mgo
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mgo
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mxc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mxc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : let
+ Balance Type : trade
+ Balance : 0
+
+ Currency : let
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : band
+ Balance Type : trade
+ Balance : 0
+
+ Currency : band
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : near
+ Balance Type : trade
+ Balance : 0
+
+ Currency : near
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xmr
+ Balance Type : trade
+ Balance : 0
+
+ Currency : xmr
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dock
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dock
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bt1
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bt1
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pearl
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pearl
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : waves
+ Balance Type : trade
+ Balance : 0
+
+ Currency : waves
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bt2
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bt2
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : reef
+ Balance Type : trade
+ Balance : 0
+
+ Currency : reef
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : iota
+ Balance Type : trade
+ Balance : 0
+
+ Currency : iota
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xmx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : xmx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : iris
+ Balance Type : trade
+ Balance : 0
+
+ Currency : iris
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cdc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cdc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ae
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ae
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : stk
+ Balance Type : trade
+ Balance : 0
+
+ Currency : stk
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : husd
+ Balance Type : trade
+ Balance : 0
+
+ Currency : husd
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : node
+ Balance Type : trade
+ Balance : 0
+
+ Currency : node
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ar
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ar
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : musk
+ Balance Type : trade
+ Balance : 0
+
+ Currency : musk
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : iost
+ Balance Type : trade
+ Balance : 0
+
+ Currency : iost
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dot2l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dot2l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pnt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pnt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eth3l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eth3l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cova
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cova
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : wnxm
+ Balance Type : trade
+ Balance : 0
+
+ Currency : wnxm
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eth3s
+ Balance Type : trade
+ Balance : 0.0000342
+
+ Currency : eth3s
+ Balance Type : frozen
+ Balance : 8483
+
+ Currency : wing
+ Balance Type : trade
+ Balance : 0
+
+ Currency : wing
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dgb
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dgb
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bsv3s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bsv3s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dot2s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dot2s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dgd
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dgd
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : zrx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : zrx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bcd
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bcd
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : aac
+ Balance Type : trade
+ Balance : 0
+
+ Currency : aac
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bch
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bch
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bsv
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bsv
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : omg
+ Balance Type : trade
+ Balance : 0
+
+ Currency : omg
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : jst
+ Balance Type : trade
+ Balance : 0
+
+ Currency : jst
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : hot
+ Balance Type : trade
+ Balance : 0
+
+ Currency : hot
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : sun
+ Balance Type : trade
+ Balance : 0
+
+ Currency : sun
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : wbtc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : wbtc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : appc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : appc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : btc
+ Balance Type : trade
+ Balance : 0.000000526
+
+ Currency : btc
+ Balance Type : frozen
+ Balance : 0.026683
+
+ Currency : sc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : sc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : rsr
+ Balance Type : trade
+ Balance : 0
+
+ Currency : rsr
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : nkn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : nkn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : qash
+ Balance Type : trade
+ Balance : 0
+
+ Currency : qash
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cvc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cvc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ardr
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ardr
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : btg
+ Balance Type : trade
+ Balance : 0
+
+ Currency : btg
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bcv
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bcv
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : link3l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : link3l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bcx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bcx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : matic
+ Balance Type : trade
+ Balance : 0
+
+ Currency : matic
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : btm
+ Balance Type : trade
+ Balance : 0
+
+ Currency : btm
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cvcoin
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cvcoin
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : rcn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : rcn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cvp
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cvp
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : link3s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : link3s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : uip
+ Balance Type : trade
+ Balance : 0
+
+ Currency : uip
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mzk
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mzk
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bts
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bts
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : rte
+ Balance Type : trade
+ Balance : 0
+
+ Currency : rte
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : salt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : salt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : btt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : btt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : rccc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : rccc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : one
+ Balance Type : trade
+ Balance : 0
+
+ Currency : one
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ong
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ong
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : lxt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : lxt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : nhbtc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : nhbtc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : abl
+ Balance Type : trade
+ Balance : 0
+
+ Currency : abl
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : nest
+ Balance Type : trade
+ Balance : 0
+
+ Currency : nest
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : glm
+ Balance Type : trade
+ Balance : 0
+
+ Currency : glm
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : storj
+ Balance Type : trade
+ Balance : 0
+
+ Currency : storj
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : hpt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : hpt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : gnx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : gnx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dht
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dht
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : abt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : abt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ugas
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ugas
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mana
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mana
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ont
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ont
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bkbt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bkbt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ruff
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ruff
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : onx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : onx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ankr
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ankr
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : rdn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : rdn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : algo
+ Balance Type : trade
+ Balance : 0
+
+ Currency : algo
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eth1s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eth1s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : rub
+ Balance Type : trade
+ Balance : 0
+
+ Currency : rub
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : gof
+ Balance Type : trade
+ Balance : 0
+
+ Currency : gof
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : but
+ Balance Type : trade
+ Balance : 0
+
+ Currency : but
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : tt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : tt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : lym
+ Balance Type : trade
+ Balance : 0
+
+ Currency : lym
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : zjlt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : zjlt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : df
+ Balance Type : trade
+ Balance : 0
+
+ Currency : df
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ast
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ast
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : wicc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : wicc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : doge
+ Balance Type : trade
+ Balance : 0
+
+ Currency : doge
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : nano
+ Balance Type : trade
+ Balance : 0
+
+ Currency : nano
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ach
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ach
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eko
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eko
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : sexc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : sexc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bel
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bel
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : uc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : uc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : qsp
+ Balance Type : trade
+ Balance : 0
+
+ Currency : qsp
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ekt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ekt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : act
+ Balance Type : trade
+ Balance : 0
+
+ Currency : act
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : loom
+ Balance Type : trade
+ Balance : 0
+
+ Currency : loom
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mkr
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mkr
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : woo
+ Balance Type : trade
+ Balance : 0
+
+ Currency : woo
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ycc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ycc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : zec
+ Balance Type : trade
+ Balance : 0
+
+ Currency : zec
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : itc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : itc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pai
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pai
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : meetone
+ Balance Type : trade
+ Balance : 0
+
+ Currency : meetone
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ren
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ren
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ela
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ela
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : hbar
+ Balance Type : trade
+ Balance : 0
+
+ Currency : hbar
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : atp
+ Balance Type : trade
+ Balance : 0
+
+ Currency : atp
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ncash
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ncash
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : elf
+ Balance Type : trade
+ Balance : 0
+
+ Currency : elf
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ada
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ada
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : icx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : icx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : req
+ Balance Type : trade
+ Balance : 0
+
+ Currency : req
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : add
+ Balance Type : trade
+ Balance : 0
+
+ Currency : add
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : vsys
+ Balance Type : trade
+ Balance : 0
+
+ Currency : vsys
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : usd01
+ Balance Type : trade
+ Balance : 0
+
+ Currency : usd01
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eos3l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eos3l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : zen
+ Balance Type : trade
+ Balance : 0
+
+ Currency : zen
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : tusd
+ Balance Type : trade
+ Balance : 0
+
+ Currency : tusd
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eoss
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eoss
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pax
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pax
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : em
+ Balance Type : trade
+ Balance : 0
+
+ Currency : em
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : hb10
+ Balance Type : trade
+ Balance : 0
+
+ Currency : hb10
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pay
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pay
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : rbtc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : rbtc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eos3s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eos3s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : rvn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : rvn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : propy
+ Balance Type : trade
+ Balance : 0
+
+ Currency : propy
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : chr
+ Balance Type : trade
+ Balance : 0
+
+ Currency : chr
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : egcc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : egcc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mln
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mln
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : adt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : adt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bft
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bft
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : she
+ Balance Type : trade
+ Balance : 0
+
+ Currency : she
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : sand
+ Balance Type : trade
+ Balance : 0
+
+ Currency : sand
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bch3l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bch3l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : kava
+ Balance Type : trade
+ Balance : 0
+
+ Currency : kava
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : adx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : adx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bch3s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bch3s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : chz
+ Balance Type : trade
+ Balance : 0
+
+ Currency : chz
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xrp
+ Balance Type : trade
+ Balance : 0.00562304308335422
+
+ Currency : xrp
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : wpr
+ Balance Type : trade
+ Balance : 0
+
+ Currency : wpr
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : idt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : idt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : tfuel
+ Balance Type : trade
+ Balance : 0
+
+ Currency : tfuel
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dka
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dka
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xrt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : xrt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : vidy
+ Balance Type : trade
+ Balance : 0
+
+ Currency : vidy
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : hc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : hc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : perp
+ Balance Type : trade
+ Balance : 0
+
+ Currency : perp
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mass
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mass
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : for
+ Balance Type : trade
+ Balance : 0
+
+ Currency : for
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : uma
+ Balance Type : trade
+ Balance : 0
+
+ Currency : uma
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : qun
+ Balance Type : trade
+ Balance : 0
+
+ Currency : qun
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : sbtc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : sbtc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : luna
+ Balance Type : trade
+ Balance : 0
+
+ Currency : luna
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pizza
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pizza
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bcha
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bcha
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : yfii
+ Balance Type : trade
+ Balance : 0
+
+ Currency : yfii
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : gas
+ Balance Type : trade
+ Balance : 0
+
+ Currency : gas
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : yee
+ Balance Type : trade
+ Balance : 0
+
+ Currency : yee
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : nexo
+ Balance Type : trade
+ Balance : 0
+
+ Currency : nexo
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : lend
+ Balance Type : trade
+ Balance : 0
+
+ Currency : lend
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : portal
+ Balance Type : trade
+ Balance : 0
+
+ Currency : portal
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eng
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eng
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bhd
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bhd
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : aave
+ Balance Type : trade
+ Balance : 0
+
+ Currency : aave
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : wan
+ Balance Type : trade
+ Balance : 0
+
+ Currency : wan
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : grt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : grt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : grs
+ Balance Type : trade
+ Balance : 0
+
+ Currency : grs
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : gt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : gt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : waxp
+ Balance Type : trade
+ Balance : 0
+
+ Currency : waxp
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : hbc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : hbc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : uni
+ Balance Type : trade
+ Balance : 0
+
+ Currency : uni
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : gsc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : gsc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ckb
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ckb
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : swftc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : swftc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : yfi
+ Balance Type : trade
+ Balance : 0
+
+ Currency : yfi
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xtz
+ Balance Type : trade
+ Balance : 0
+
+ Currency : xtz
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : avax
+ Balance Type : trade
+ Balance : 0
+
+ Currency : avax
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eon
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eon
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xrp3s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : xrp3s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eop
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eop
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eos
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eos
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : value
+ Balance Type : trade
+ Balance : 0
+
+ Currency : value
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : fair
+ Balance Type : trade
+ Balance : 0
+
+ Currency : fair
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ht
+ Balance Type : trade
+ Balance : 0.0024
+
+ Currency : ht
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bix
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bix
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ost
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ost
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : skm
+ Balance Type : trade
+ Balance : 0
+
+ Currency : skm
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : skl
+ Balance Type : trade
+ Balance : 0
+
+ Currency : skl
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : gtc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : gtc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : 1inch
+ Balance Type : trade
+ Balance : 0
+
+ Currency : 1inch
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ocn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ocn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : zil
+ Balance Type : trade
+ Balance : 0
+
+ Currency : zil
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xrp3l
+ Balance Type : trade
+ Balance : 0.0000534
+
+ Currency : xrp3l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xem
+ Balance Type : trade
+ Balance : 0
+
+ Currency : xem
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : nas
+ Balance Type : trade
+ Balance : 0
+
+ Currency : nas
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : comp
+ Balance Type : trade
+ Balance : 0
+
+ Currency : comp
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : wtc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : wtc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : hvt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : hvt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xvg
+ Balance Type : trade
+ Balance : 0
+
+ Currency : xvg
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : iq
+ Balance Type : trade
+ Balance : 0
+
+ Currency : iq
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : tnb
+ Balance Type : trade
+ Balance : 0
+
+ Currency : tnb
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : btc3s
+ Balance Type : trade
+ Balance : 0.0000704
+
+ Currency : btc3s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : 18c
+ Balance Type : trade
+ Balance : 0
+
+ Currency : 18c
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : powr
+ Balance Type : trade
+ Balance : 0
+
+ Currency : powr
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pvt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pvt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : btc3l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : btc3l
+ Balance Type : frozen
+ Balance : 1.996
+
+ Currency : ctxc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ctxc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : tnt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : tnt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : nbs
+ Balance Type : trade
+ Balance : 0
+
+ Currency : nbs
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : fsn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : fsn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : hive
+ Balance Type : trade
+ Balance : 0
+
+ Currency : hive
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : iic
+ Balance Type : trade
+ Balance : 0
+
+ Currency : iic
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : kmd
+ Balance Type : trade
+ Balance : 0
+
+ Currency : kmd
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bags
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bags
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : steem
+ Balance Type : trade
+ Balance : 0
+
+ Currency : steem
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : lol
+ Balance Type : trade
+ Balance : 0
+
+ Currency : lol
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dot
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dot
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cmt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cmt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ncc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ncc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : top
+ Balance Type : trade
+ Balance : 0
+
+ Currency : top
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : get
+ Balance Type : trade
+ Balance : 0
+
+ Currency : get
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : gve
+ Balance Type : trade
+ Balance : 0
+
+ Currency : gve
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cvnt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cvnt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : tos
+ Balance Type : trade
+ Balance : 0
+
+ Currency : tos
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : fti
+ Balance Type : trade
+ Balance : 0
+
+ Currency : fti
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : smt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : smt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : man
+ Balance Type : trade
+ Balance : 0
+
+ Currency : man
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cnns
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cnns
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : knc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : knc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cnn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cnn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bifi
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bifi
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ftt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ftt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pha
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pha
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : snc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : snc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : zla
+ Balance Type : trade
+ Balance : 0
+
+ Currency : zla
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : blz
+ Balance Type : trade
+ Balance : 0
+
+ Currency : blz
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : api3
+ Balance Type : trade
+ Balance : 0
+
+ Currency : api3
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : chat
+ Balance Type : trade
+ Balance : 0
+
+ Currency : chat
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eosdac
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eosdac
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : yamv2
+ Balance Type : trade
+ Balance : 0
+
+ Currency : yamv2
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : snt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : snt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : atom
+ Balance Type : trade
+ Balance : 0
+
+ Currency : atom
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : snx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : snx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : soc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : soc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dac
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dac
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : seele
+ Balance Type : trade
+ Balance : 0
+
+ Currency : seele
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dai
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dai
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : gusd
+ Balance Type : trade
+ Balance : 0
+
+ Currency : gusd
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : sol
+ Balance Type : trade
+ Balance : 0
+
+ Currency : sol
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : hit
+ Balance Type : trade
+ Balance : 0
+
+ Currency : hit
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ltc3s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ltc3s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : etc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : etc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dat
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dat
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : etf
+ Balance Type : trade
+ Balance : 0
+
+ Currency : etf
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ogo
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ogo
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ogn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ogn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 3528.75950756236086578
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0.000000000000000002
+
+ Currency : eth
+ Balance Type : trade
+ Balance : 0
+
+ Currency : eth
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mco
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mco
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : topc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : topc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : aidoc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : aidoc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : titan
+ Balance Type : trade
+ Balance : 0
+
+ Currency : titan
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : neo
+ Balance Type : trade
+ Balance : 0
+
+ Currency : neo
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : sushi
+ Balance Type : trade
+ Balance : 0
+
+ Currency : sushi
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mta
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mta
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : lrc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : lrc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ltc3l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ltc3l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : renbtc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : renbtc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ven
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ven
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : etn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : etn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : swrv
+ Balance Type : trade
+ Balance : 0
+
+ Currency : swrv
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : firo
+ Balance Type : trade
+ Balance : 0
+
+ Currency : firo
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : wgp
+ Balance Type : trade
+ Balance : 0
+
+ Currency : wgp
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : new
+ Balance Type : trade
+ Balance : 0
+
+ Currency : new
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : gxc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : gxc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mtl
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mtl
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dbc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dbc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : vet
+ Balance Type : trade
+ Balance : 0
+
+ Currency : vet
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : trb
+ Balance Type : trade
+ Balance : 0
+
+ Currency : trb
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mtn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mtn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : fil3s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : fil3s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bnt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bnt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : lba
+ Balance Type : trade
+ Balance : 0
+
+ Currency : lba
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : oxt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : oxt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : usdc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : usdc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : fil3l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : fil3l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : utk
+ Balance Type : trade
+ Balance : 0
+
+ Currency : utk
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : nvt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : nvt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mtx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mtx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : wxt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : wxt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : edu
+ Balance Type : trade
+ Balance : 0
+
+ Currency : edu
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : trx
+ Balance Type : trade
+ Balance : 0.002358
+
+ Currency : trx
+ Balance Type : frozen
+ Balance : 69069.31
+
+ Currency : dash
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dash
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mds
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mds
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : nuls
+ Balance Type : trade
+ Balance : 0
+
+ Currency : nuls
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mdx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mdx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pond
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pond
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : lina
+ Balance Type : trade
+ Balance : 0
+
+ Currency : lina
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bor
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bor
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : lsk
+ Balance Type : trade
+ Balance : 0
+
+ Currency : lsk
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : bot
+ Balance Type : trade
+ Balance : 0
+
+ Currency : bot
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : nsure
+ Balance Type : trade
+ Balance : 0
+
+ Currency : nsure
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : link
+ Balance Type : trade
+ Balance : 0.0099
+
+ Currency : link
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : box
+ Balance Type : trade
+ Balance : 0
+
+ Currency : box
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : akro
+ Balance Type : trade
+ Balance : 0
+
+ Currency : akro
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : meet
+ Balance Type : trade
+ Balance : 0
+
+ Currency : meet
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : qtum
+ Balance Type : trade
+ Balance : 0
+
+ Currency : qtum
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : uni2l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : uni2l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : arpa
+ Balance Type : trade
+ Balance : 0
+
+ Currency : arpa
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dta
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dta
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : dcr
+ Balance Type : trade
+ Balance : 0
+
+ Currency : dcr
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : uuu
+ Balance Type : trade
+ Balance : 0
+
+ Currency : uuu
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : uni2s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : uni2s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cre
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cre
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : zec3l
+ Balance Type : trade
+ Balance : 0
+
+ Currency : zec3l
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : kan
+ Balance Type : trade
+ Balance : 0
+
+ Currency : kan
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : beth
+ Balance Type : trade
+ Balance : 0
+
+ Currency : beth
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ltc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ltc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : zec3s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : zec3s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : inc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : inc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mex
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mex
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cro
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cro
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : mvl
+ Balance Type : trade
+ Balance : 0
+
+ Currency : mvl
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : inj
+ Balance Type : trade
+ Balance : 0
+
+ Currency : inj
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : evx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : evx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ant
+ Balance Type : trade
+ Balance : 0
+
+ Currency : ant
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : crv
+ Balance Type : trade
+ Balance : 0
+
+ Currency : crv
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : cru
+ Balance Type : trade
+ Balance : 0
+
+ Currency : cru
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : btc1s
+ Balance Type : trade
+ Balance : 0
+
+ Currency : btc1s
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : srn
+ Balance Type : trade
+ Balance : 0
+
+ Currency : srn
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : datx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : datx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : badger
+ Balance Type : trade
+ Balance : 0.91950210527285626
+
+ Currency : badger
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pols
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pols
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : pc
+ Balance Type : trade
+ Balance : 0
+
+ Currency : pc
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : poly
+ Balance Type : trade
+ Balance : 0
+
+ Currency : poly
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xlm
+ Balance Type : trade
+ Balance : 0
+
+ Currency : xlm
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : lamb
+ Balance Type : trade
+ Balance : 0
+
+ Currency : lamb
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : phx
+ Balance Type : trade
+ Balance : 0
+
+ Currency : phx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : front
+ Balance Type : trade
+ Balance : 0
+
+ Currency : front
+ Balance Type : frozen
+ Balance : 0
+
+
+Account ID : 18781342
+Account Type : margin
+Account State : working
+Subtype : bsvusdt
+
+ Currency : bsv
+ Balance Type : trade
+ Balance : 0.000059073599142826
+
+ Currency : bsv
+ Balance Type : frozen
+ Balance : 50.8113
+
+ Currency : bsv
+ Balance Type : loan
+ Balance : 0
+
+ Currency : bsv
+ Balance Type : interest
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 0.000900000000003071
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0.000000000000000003
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : -6688.376
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : -21.41935655
+
+
+Account ID : 18837978
+Account Type : margin
+Account State : working
+Subtype : htusdt
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 0.00000000800000194
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+ Currency : ht
+ Balance Type : trade
+ Balance : 0.00947382462977359
+
+ Currency : ht
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ht
+ Balance Type : loan
+ Balance : 0
+
+ Currency : ht
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 18739313
+Account Type : margin
+Account State : working
+Subtype : ethusdt
+
+ Currency : eth
+ Balance Type : trade
+ Balance : 0.000990739293469514
+
+ Currency : eth
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : eth
+ Balance Type : loan
+ Balance : -0.00158068
+
+ Currency : eth
+ Balance Type : interest
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 1053.900375716000003242
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0.000000000000000001
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 18692354
+Account Type : margin
+Account State : working
+Subtype : yfiusdt
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+ Currency : yfi
+ Balance Type : trade
+ Balance : 0.000981342
+
+ Currency : yfi
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : yfi
+ Balance Type : loan
+ Balance : 0
+
+ Currency : yfi
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 18821595
+Account Type : margin
+Account State : working
+Subtype : xrpusdt
+
+ Currency : xrp
+ Balance Type : trade
+ Balance : 0
+
+ Currency : xrp
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : xrp
+ Balance Type : loan
+ Balance : 0
+
+ Currency : xrp
+ Balance Type : interest
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 18792019
+Account Type : margin
+Account State : working
+Subtype : vetusdt
+
+ Currency : vet
+ Balance Type : trade
+ Balance : 299.04182932
+
+ Currency : vet
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : vet
+ Balance Type : loan
+ Balance : 0
+
+ Currency : vet
+ Balance Type : interest
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 0.0000000096
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 18736093
+Account Type : margin
+Account State : working
+Subtype : trxusdt
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 5.843408887800000024
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0.000000000000000001
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+ Currency : trx
+ Balance Type : trade
+ Balance : 0.684836479013854132
+
+ Currency : trx
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : trx
+ Balance Type : loan
+ Balance : 0
+
+ Currency : trx
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 18767134
+Account Type : margin
+Account State : working
+Subtype : renusdt
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 0.00000000702
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : 0
+
+ Currency : ren
+ Balance Type : trade
+ Balance : 8.30309806
+
+ Currency : ren
+ Balance Type : frozen
+ Balance : 0
+
+ Currency : ren
+ Balance Type : loan
+ Balance : 0
+
+ Currency : ren
+ Balance Type : interest
+ Balance : 0
+
+
+Account ID : 17863569
+Account Type : otc
+Account State : working
+Subtype :
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 0
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0
+
+
+Account ID : 18788774
+Account Type : margin
+Account State : working
+Subtype : xmrusdt
+
+ Currency : usdt
+ Balance Type : trade
+ Balance : 0.00000000800000496
+
+ Currency : usdt
+ Balance Type : frozen
+ Balance : 0.000000000000000001
+
+ Currency : usdt
+ Balance Type : loan
+ Balance : -7994.332
+
+ Currency : usdt
+ Balance Type : interest
+ Balance : -31.33522464
+
+ Currency : xmr
+ Balance Type : trade
+ Balance : 0.000074003175294476
+
+ Currency : xmr
+ Balance Type : frozen
+ Balance : 81.4258
+
+ Currency : xmr
+ Balance Type : loan
+ Balance : 0
+
+ Currency : xmr
+ Balance Type : interest
+ Balance : 0
+
+
+
+Process finished with exit code 0
+
+'''
+
+
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+LogInfo.output("====== (SDK encapsulated api) not recommend for low performance and frequence limitation ======")
+account_balance_list = account_client.get_account_balance()
+if account_balance_list and len(account_balance_list):
+ for account_obj in account_balance_list:
+ account_obj.print_object()
+ print()
\ No newline at end of file
diff --git a/example/account/get_account_balance_by_subuid.py b/example/account/get_account_balance_by_subuid.py
new file mode 100644
index 0000000..8d9014c
--- /dev/null
+++ b/example/account/get_account_balance_by_subuid.py
@@ -0,0 +1,12 @@
+from huobi.client.account import AccountClient
+from huobi.constant import *
+
+# get accounts
+from huobi.utils import *
+from example.api_key import *
+# 子账户财产
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+list_obj = account_client.get_account_balance_by_subuid(sub_uid=g_sub_uid)
+LogInfo.output_list(list_obj)
+
diff --git a/example/account/get_account_balance_sufficient.py b/example/account/get_account_balance_sufficient.py
new file mode 100644
index 0000000..fb46941
--- /dev/null
+++ b/example/account/get_account_balance_sufficient.py
@@ -0,0 +1,33 @@
+from huobi.client.account import AccountClient
+
+# get accounts
+from huobi.utils import *
+from example.api_key import *
+
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+# list_obj = account_client.get_accounts()
+# if list_obj and len(list_obj):
+# for account_obj in list_obj:
+# list_obj = account_client.get_balance(account_id=account_obj.id)
+# LogInfo.output("===== {account_id} , {account_type} =====".format(account_id=account_obj.id, account_type=account_obj.type))
+# if len(list_obj):
+# for obj in list_obj:
+# if float(obj.balance) > 0.1: # only show account with balance
+# obj.print_object()
+# print()
+
+LogInfo.output("====== (SDK encapsulated api) not recommend for low performance and frequence limitation ======")
+account_balance_list = account_client.get_account_balance()
+if account_balance_list and len(account_balance_list):
+ for account_balance_obj in account_balance_list:
+ if account_balance_obj and len(account_balance_obj.list):
+ PrintBasic.print_basic(account_balance_obj.id, "ID")
+ PrintBasic.print_basic(account_balance_obj.type, "Account Type")
+ PrintBasic.print_basic(account_balance_obj.state, "Account State")
+ PrintBasic.print_basic(account_balance_obj.subtype, "Subtype")
+ for balance_obj in account_balance_obj.list:
+ if float(balance_obj.balance) > 0.1: # only show account with balance
+ balance_obj.print_object("\t")
+ print()
+ print()
\ No newline at end of file
diff --git a/example/account/get_account_by_type_symbol.py b/example/account/get_account_by_type_symbol.py
new file mode 100644
index 0000000..f79e083
--- /dev/null
+++ b/example/account/get_account_by_type_symbol.py
@@ -0,0 +1,34 @@
+from huobi.client.account import AccountClient
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+
+# get accounts
+from huobi.utils import *
+from example.api_key import *
+
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+
+LogInfo.output("========= case 1 get spot (SDK encapsulated api) =========")
+account_obj = account_client.get_account_by_type_and_symbol(account_type=AccountType.SPOT, symbol=None)
+account_obj.print_object()
+
+LogInfo.output("========= case 2 get margin-linkusdt (SDK encapsulated api) =========")
+account_obj = account_client.get_account_by_type_and_symbol(account_type=AccountType.MARGIN, symbol="linkusdt")
+if account_obj:
+ account_obj.print_object()
+
+LogInfo.output("========= case 3 get margin-linkusdt (SDK encapsulated api) =========")
+account_obj = account_client.get_account_by_type_and_symbol(account_type=AccountType.SUPER_MARGIN, symbol=None)
+if account_obj:
+ account_obj.print_object()
+
+LogInfo.output("========= case 4 get margin-linkusdt (original api, supported) =========")
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+list_obj = margin_client.get_margin_account_balance(symbol="linkusdt")
+LogInfo.output_list(list_obj)
+
+LogInfo.output("========= case 5 get cross-margin (original api, supported) =========")
+print(margin_client)
+account_balance = margin_client.get_cross_margin_account_balance()
+account_balance.print_object()
\ No newline at end of file
diff --git a/example/account/get_account_history.py b/example/account/get_account_history.py
new file mode 100644
index 0000000..e53e16e
--- /dev/null
+++ b/example/account/get_account_history.py
@@ -0,0 +1,11 @@
+from huobi.client.account import AccountClient
+
+# get accounts
+from huobi.utils import *
+from example.api_key import *
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+
+account_history = account_client.get_account_history(account_id=g_account_id, start_time=1600827872000, size=4)
+LogInfo.output_list(account_history["data"])
+LogInfo.output('Next Id: %s' % (account_history["next_id"]))
diff --git a/example/account/get_account_ledger.py b/example/account/get_account_ledger.py
new file mode 100644
index 0000000..a967a37
--- /dev/null
+++ b/example/account/get_account_ledger.py
@@ -0,0 +1,8 @@
+from huobi.client.account import AccountClient
+from huobi.utils import *
+from example.api_key import *
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+
+list_obj = account_client.get_account_ledger(account_id=g_account_id)
+LogInfo.output_list(list_obj)
diff --git a/example/account/get_account_point.py b/example/account/get_account_point.py
new file mode 100644
index 0000000..6da04ef
--- /dev/null
+++ b/example/account/get_account_point.py
@@ -0,0 +1,8 @@
+from huobi.client.account import AccountClient
+from example.api_key import *
+
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+
+account_point_result = account_client.get_account_point()
+account_point_result.print_object()
diff --git a/example/account/get_accounts.py b/example/account/get_accounts.py
new file mode 100644
index 0000000..ecaf373
--- /dev/null
+++ b/example/account/get_accounts.py
@@ -0,0 +1,12 @@
+from huobi.client.account import AccountClient
+
+# get accounts
+from huobi.utils import *
+from example.api_key import *
+
+
+account_client = AccountClient(api_key=g_api_key,secret_key=g_secret_key)
+
+list_obj = account_client.get_accounts()
+LogInfo.output_list(list_obj)
+
diff --git a/example/account/get_aggregated_subuser_balance.py b/example/account/get_aggregated_subuser_balance.py
new file mode 100644
index 0000000..5854f68
--- /dev/null
+++ b/example/account/get_aggregated_subuser_balance.py
@@ -0,0 +1,10 @@
+from huobi.client.account import AccountClient
+
+# get accounts
+from huobi.utils import *
+from example.api_key import *
+
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+list_obj = account_client.get_aggregated_subuser_balance()
+LogInfo.output_list(list_obj)
diff --git a/example/account/get_balance.py b/example/account/get_balance.py
new file mode 100644
index 0000000..c050d7f
--- /dev/null
+++ b/example/account/get_balance.py
@@ -0,0 +1,9 @@
+from huobi.client.account import AccountClient
+
+# get accounts
+from huobi.utils import *
+from example.api_key import *
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+list_obj = account_client.get_balance(account_id=g_account_id)
+LogInfo.output_list(list_obj)
\ No newline at end of file
diff --git a/example/account/post_account_transfer.py b/example/account/post_account_transfer.py
new file mode 100644
index 0000000..fecf2a8
--- /dev/null
+++ b/example/account/post_account_transfer.py
@@ -0,0 +1,12 @@
+from huobi.client.account import AccountClient
+from huobi.constant import *
+
+account_client = AccountClient(api_key=g_api_key, secret_key=g_secret_key)
+# transfer_result = account_client.post_account_transfer(111859319, 'spot', 10354000, 147509118, 'spot', 13956126, 'trx', 3600)
+# transfer_result.print_object()
+
+# transfer_result = account_client.post_account_transfer(111859319, 'spot', 10354000, 147991959, 'spot', 14026125, 'usdt', 3600)
+# transfer_result.print_object()
+
+transfer_result = account_client.post_account_transfer(111859319, 'spot', 10354000, 141403659, 'spot', 13082796, 'usdt', 32.21)
+transfer_result.print_object()
diff --git a/example/account/post_point_transfer.py b/example/account/post_point_transfer.py
new file mode 100644
index 0000000..f4db684
--- /dev/null
+++ b/example/account/post_point_transfer.py
@@ -0,0 +1,8 @@
+from huobi.client.account import AccountClient
+from huobi.constant import *
+
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+
+point_transfer_result = account_client.post_point_transfer(from_uid=111859319, to_uid=124409916, group_id=0, amount=10)
+point_transfer_result.print_object()
diff --git a/example/account/post_sub_user_management.py b/example/account/post_sub_user_management.py
new file mode 100644
index 0000000..679b338
--- /dev/null
+++ b/example/account/post_sub_user_management.py
@@ -0,0 +1,13 @@
+
+from huobi.client.account import AccountClient
+from huobi.constant import *
+
+# get accounts
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+
+ret = account_client.post_sub_uid_management(sub_uid=g_sub_uid, action=SubUidAction.LOCK)
+ret.print_object()
+
+ret = account_client.post_sub_uid_management(sub_uid=g_sub_uid, action=SubUidAction.UNLOCK)
+ret.print_object()
\ No newline at end of file
diff --git a/example/account/post_transfer_between_futures_and_pro.py b/example/account/post_transfer_between_futures_and_pro.py
new file mode 100644
index 0000000..33ab7cc
--- /dev/null
+++ b/example/account/post_transfer_between_futures_and_pro.py
@@ -0,0 +1,19 @@
+
+from huobi.client.account import AccountClient
+from huobi.constant import *
+from huobi.utils import *
+import time
+
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+transfer_order_id = account_client.transfer_between_futures_and_pro(currency="trx", amount=200, transfer_type=TransferFuturesPro.TO_FUTURES)
+LogInfo.output("transfer from pro to future Order Id : {id}".format(id=transfer_order_id))
+
+# need wait a minute
+time.sleep(2)
+
+transfer_order_id = account_client.transfer_between_futures_and_pro(currency="trx", amount=200, transfer_type=TransferFuturesPro.TO_PRO)
+LogInfo.output("transfer from future to pro Order Id : {id}".format(id=transfer_order_id))
+
+
+
diff --git a/example/account/post_transfer_between_parent_and_subuser.py b/example/account/post_transfer_between_parent_and_subuser.py
new file mode 100644
index 0000000..a0a959f
--- /dev/null
+++ b/example/account/post_transfer_between_parent_and_subuser.py
@@ -0,0 +1,15 @@
+
+from huobi.client.account import AccountClient
+from huobi.constant import *
+from huobi.utils import *
+
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key)
+transfer_order_id = account_client.transfer_between_parent_and_subuser(sub_uid=g_sub_uid, currency="usdt", amount=10, transfer_type=TransferMasterType.OUT)
+LogInfo.output("transfer from master to subuser Order Id : {id}".format(id=transfer_order_id))
+
+transfer_order_id = account_client.transfer_between_parent_and_subuser(sub_uid=g_sub_uid, currency="usdt", amount=10, transfer_type=TransferMasterType.IN)
+LogInfo.output("transfer from subuser to master Order Id : {id}".format(id=transfer_order_id))
+
+
+
diff --git a/example/account/req_account_balance_list.py b/example/account/req_account_balance_list.py
new file mode 100644
index 0000000..5423ae5
--- /dev/null
+++ b/example/account/req_account_balance_list.py
@@ -0,0 +1,10 @@
+from huobi.client.account import AccountClient
+from huobi.constant import *
+
+
+def callback(account_balance_req: 'AccountBalanceReq'):
+ account_balance_req.print_object()
+
+
+account_client = AccountClient(api_key=g_api_key, secret_key=g_secret_key)
+account_client.req_account_balance(callback=callback, client_req_id=None)
diff --git a/example/account/sub_account_update.py b/example/account/sub_account_update.py
new file mode 100644
index 0000000..fdd9a2f
--- /dev/null
+++ b/example/account/sub_account_update.py
@@ -0,0 +1,15 @@
+from huobi.client.account import AccountClient
+from huobi.constant import *
+
+
+def callback(account_change_event: 'AccountChangeEvent'):
+ account_change_event.print_object()
+ print()
+
+
+account_client = AccountClient(api_key=g_api_key,
+ secret_key=g_secret_key,
+ init_log=True)
+# account_client.sub_account_update(AccountBalanceMode.TOTAL, callback)
+account_client.sub_account_update(AccountBalanceMode.BALANCE, callback)
+
diff --git a/example/algo/get_open_orders.py b/example/algo/get_open_orders.py
new file mode 100644
index 0000000..17161c1
--- /dev/null
+++ b/example/algo/get_open_orders.py
@@ -0,0 +1,10 @@
+from huobi.client.algo import AlgoClient
+from huobi.constant import *
+from huobi.utils import *
+
+symbol_test = "adausdt"
+account_id = g_account_id
+
+algo_client = AlgoClient(api_key=g_api_key, secret_key=g_secret_key)
+result = algo_client.get_open_orders()
+LogInfo.output_list(result)
diff --git a/example/algo/get_order.py b/example/algo/get_order.py
new file mode 100644
index 0000000..d606d92
--- /dev/null
+++ b/example/algo/get_order.py
@@ -0,0 +1,10 @@
+from huobi.client.algo import AlgoClient
+from huobi.constant import *
+
+account_id = g_account_id
+client_order_id = "test002"
+
+# get specific order by clientOrderId
+algo_client = AlgoClient(api_key=g_api_key, secret_key=g_secret_key)
+result = algo_client.get_order(client_order_id)
+result.print_object()
diff --git a/example/algo/get_order_history.py b/example/algo/get_order_history.py
new file mode 100644
index 0000000..896d5f9
--- /dev/null
+++ b/example/algo/get_order_history.py
@@ -0,0 +1,10 @@
+from huobi.client.algo import AlgoClient
+from huobi.constant import *
+from huobi.utils import *
+
+symbol_test = "adausdt"
+account_id = g_account_id
+
+algo_client = AlgoClient(api_key=g_api_key, secret_key=g_secret_key)
+result = algo_client.get_order_history(symbol_test, AlgoOrderStatus.TRIGGERED)
+LogInfo.output_list(result)
diff --git a/example/algo/post_cancel_algo_orders.py b/example/algo/post_cancel_algo_orders.py
new file mode 100644
index 0000000..272ba81
--- /dev/null
+++ b/example/algo/post_cancel_algo_orders.py
@@ -0,0 +1,17 @@
+from huobi.client.algo import AlgoClient
+from huobi.constant import *
+from huobi.utils import *
+
+symbol_test = "adausdt"
+account_id = g_account_id
+
+orders_to_cancel = ["test003", "test001"]
+algo_client = AlgoClient(api_key=g_api_key, secret_key=g_secret_key)
+result = algo_client.cancel_orders(orders_to_cancel)
+result.print_object()
+
+# order_id = algo_client.create_order(symbol=symbol_test, account_id=account_id, order_type=OrderType.BUY_MARKET, source=OrderSource.API, amount=5.0, price=1.292)
+# LogInfo.output("created order id : {id}".format(id=order_id))
+#
+# order_id = algo_client.create_order(symbol=symbol_test, account_id=account_id, order_type=OrderType.SELL_MARKET, source=OrderSource.API, amount=1.77, price=None)
+# LogInfo.output("created order id : {id}".format(id=order_id))
diff --git a/example/algo/post_create_algo_order.py b/example/algo/post_create_algo_order.py
new file mode 100644
index 0000000..c14670a
--- /dev/null
+++ b/example/algo/post_create_algo_order.py
@@ -0,0 +1,12 @@
+from huobi.client.algo import AlgoClient
+from huobi.constant import *
+from huobi.utils import *
+
+symbol_test = "adausdt"
+account_id = g_account_id
+
+algo_client = AlgoClient(api_key=g_api_key, secret_key=g_secret_key)
+order_id = algo_client.create_order(symbol=symbol_test, account_id=account_id, order_side=OrderSide.BUY,
+ order_type=AlgoOrderType.LIMIT, order_size=65, order_price=0.08, stop_price=0.085,
+ client_order_id="test004")
+LogInfo.output("created order id : {id}".format(id=order_id))
diff --git a/example/api_key.py b/example/api_key.py
new file mode 100644
index 0000000..7ca78bb
--- /dev/null
+++ b/example/api_key.py
@@ -0,0 +1,3 @@
+g_api_key = "e7f941dd-4167913c-mjlpdje3ld-f97b3"
+g_secret_key = "f06af3d0-eaf3e4ff-9f0e931f-43aec"
+g_account_id = 18788142
\ No newline at end of file
diff --git a/example/etf/get_etf_swap_config.py b/example/etf/get_etf_swap_config.py
new file mode 100644
index 0000000..4d88659
--- /dev/null
+++ b/example/etf/get_etf_swap_config.py
@@ -0,0 +1,16 @@
+from huobi.client.etf import EtfClient
+
+
+etf_client = EtfClient()
+etf_config = etf_client.get_etf_swap_config("hb10")
+etf_config.print_object()
+
+
+
+
+
+
+
+
+
+
diff --git a/example/etf/get_etf_swap_list.py b/example/etf/get_etf_swap_list.py
new file mode 100644
index 0000000..2e355d7
--- /dev/null
+++ b/example/etf/get_etf_swap_list.py
@@ -0,0 +1,24 @@
+from huobi.client.etf import EtfClient
+from huobi.constant import *
+from huobi.utils import *
+
+
+etf_client = EtfClient(api_key=g_api_key, secret_key=g_secret_key)
+etf_list = etf_client.get_etf_swap_list(etf_name="hb10", offset=0, size=20)
+LogInfo.output_list(etf_list)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/etf/post_etf_swap_in.py b/example/etf/post_etf_swap_in.py
new file mode 100644
index 0000000..a1df864
--- /dev/null
+++ b/example/etf/post_etf_swap_in.py
@@ -0,0 +1,23 @@
+from huobi.client.etf import EtfClient
+from huobi.constant import *
+
+etf_client = EtfClient(api_key=g_api_key, secret_key=g_secret_key)
+etf_swap_ret = etf_client.post_etf_swap_in("hb10", 1000)
+etf_swap_ret.print_object()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/etf/post_etf_swap_out.py b/example/etf/post_etf_swap_out.py
new file mode 100644
index 0000000..7ebe90b
--- /dev/null
+++ b/example/etf/post_etf_swap_out.py
@@ -0,0 +1,22 @@
+from huobi.client.etf import EtfClient
+from huobi.constant import *
+
+etf_client = EtfClient(api_key=g_api_key, secret_key=g_secret_key)
+etf_swap_ret = etf_client.post_etf_swap_out("hb10", 1000)
+etf_swap_ret.print_object()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/generic/get_exchange_currencies.py b/example/generic/get_exchange_currencies.py
new file mode 100644
index 0000000..9f055bc
--- /dev/null
+++ b/example/generic/get_exchange_currencies.py
@@ -0,0 +1,9 @@
+from huobi.client.generic import GenericClient
+from huobi.utils import *
+
+
+generic_client = GenericClient()
+list_obj = generic_client.get_exchange_currencies()
+LogInfo.output("---- Supported currency ----")
+for currency in list_obj:
+ LogInfo.output(currency)
\ No newline at end of file
diff --git a/example/generic/get_exchange_info.py b/example/generic/get_exchange_info.py
new file mode 100644
index 0000000..4897240
--- /dev/null
+++ b/example/generic/get_exchange_info.py
@@ -0,0 +1,13 @@
+from huobi.client.generic import GenericClient
+from huobi.utils import *
+
+
+generic_client = GenericClient()
+list_obj = generic_client.get_exchange_info()
+LogInfo.output("---- Supported symbols ----")
+for symbol in list_obj.symbol_list:
+ LogInfo.output(symbol.symbol)
+
+LogInfo.output("---- Supported currencies ----");
+for currency in list_obj.currencies:
+ LogInfo.output(currency)
diff --git a/example/generic/get_exchange_symbols.py b/example/generic/get_exchange_symbols.py
new file mode 100644
index 0000000..7c996c4
--- /dev/null
+++ b/example/generic/get_exchange_symbols.py
@@ -0,0 +1,13 @@
+from huobi.client.generic import GenericClient
+from huobi.utils import *
+
+
+generic_client = GenericClient()
+list_obj = generic_client.get_exchange_symbols()
+if len(list_obj):
+ for idx, row in enumerate(list_obj):
+ LogInfo.output("------- number " + str(idx) + " -------")
+ row.print_object()
+
+
+
diff --git a/example/generic/get_exchange_timestamp.py b/example/generic/get_exchange_timestamp.py
new file mode 100644
index 0000000..6ffad7c
--- /dev/null
+++ b/example/generic/get_exchange_timestamp.py
@@ -0,0 +1,8 @@
+from huobi.client.generic import GenericClient
+from huobi.utils import *
+
+
+generic_client = GenericClient()
+ts = generic_client.get_exchange_timestamp()
+LogInfo.output(ts)
+
diff --git a/example/generic/get_market_status.py b/example/generic/get_market_status.py
new file mode 100644
index 0000000..2b8c2ff
--- /dev/null
+++ b/example/generic/get_market_status.py
@@ -0,0 +1,8 @@
+from huobi.client.generic import GenericClient
+
+generic_client = GenericClient()
+market_status = generic_client.get_market_status()
+print(market_status)
+
+
+
diff --git a/example/generic/get_reference_currencies.py b/example/generic/get_reference_currencies.py
new file mode 100644
index 0000000..1d0379a
--- /dev/null
+++ b/example/generic/get_reference_currencies.py
@@ -0,0 +1,13 @@
+from huobi.client.generic import GenericClient
+from huobi.utils import *
+
+
+generic_client = GenericClient()
+
+list_obj = generic_client.get_reference_currencies()
+LogInfo.output_list(list_obj)
+
+
+list_obj = generic_client.get_reference_currencies(currency="usdt")
+LogInfo.output_list(list_obj)
+
diff --git a/example/generic/get_system_status.py b/example/generic/get_system_status.py
new file mode 100644
index 0000000..7f315db
--- /dev/null
+++ b/example/generic/get_system_status.py
@@ -0,0 +1,12 @@
+from huobi.client.generic import GenericClient
+
+
+"""
+GET https://status.huobigroup.com/api/v2/summary.json
+"""
+generic_client = GenericClient()
+system_status = generic_client.get_system_status()
+print(system_status)
+
+
+
diff --git a/example/margin/get_cross_margin_account_balance.py b/example/margin/get_cross_margin_account_balance.py
new file mode 100644
index 0000000..8e6ccc1
--- /dev/null
+++ b/example/margin/get_cross_margin_account_balance.py
@@ -0,0 +1,9 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+account_balance = margin_client.get_cross_margin_account_balance()
+account_balance.print_object()
+
+
diff --git a/example/margin/get_cross_margin_loan_info.py b/example/margin/get_cross_margin_loan_info.py
new file mode 100644
index 0000000..0b626f3
--- /dev/null
+++ b/example/margin/get_cross_margin_loan_info.py
@@ -0,0 +1,8 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+list_obj = margin_client.get_cross_margin_loan_info()
+LogInfo.output_list(list_obj)
+
diff --git a/example/margin/get_cross_margin_loan_orders.py b/example/margin/get_cross_margin_loan_orders.py
new file mode 100644
index 0000000..8b9ced7
--- /dev/null
+++ b/example/margin/get_cross_margin_loan_orders.py
@@ -0,0 +1,16 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+
+# no filter
+list_obj = margin_client.get_cross_margin_loan_orders()
+LogInfo.output_list(list_obj)
+
+# filter by state
+list_obj = margin_client.get_cross_margin_loan_orders(state=LoanOrderState.ACCRUAL)
+LogInfo.output_list(list_obj)
+
+
diff --git a/example/margin/get_general_repayment_loan_records.py b/example/margin/get_general_repayment_loan_records.py
new file mode 100644
index 0000000..d37c0c2
--- /dev/null
+++ b/example/margin/get_general_repayment_loan_records.py
@@ -0,0 +1,12 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import LogInfo
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+
+list_result = margin_client.get_general_repayment_loan_records(limit=10)
+LogInfo.output_list(list_result)
+
+
+
+
diff --git a/example/margin/get_margin_account_balance.py b/example/margin/get_margin_account_balance.py
new file mode 100644
index 0000000..5bf1a7f
--- /dev/null
+++ b/example/margin/get_margin_account_balance.py
@@ -0,0 +1,8 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+list_obj = margin_client.get_margin_account_balance(symbol="eosusdt")
+LogInfo.output_list(list_obj)
+
diff --git a/example/margin/get_margin_loan_info.py b/example/margin/get_margin_loan_info.py
new file mode 100644
index 0000000..ff519f9
--- /dev/null
+++ b/example/margin/get_margin_loan_info.py
@@ -0,0 +1,8 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+list_obj = margin_client.get_margin_loan_info(symbols="btcusdt,ethusdt,eosusdt")
+LogInfo.output_list(list_obj)
+
diff --git a/example/margin/get_margin_loan_orders.py b/example/margin/get_margin_loan_orders.py
new file mode 100644
index 0000000..0ae699f
--- /dev/null
+++ b/example/margin/get_margin_loan_orders.py
@@ -0,0 +1,8 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+list_obj = margin_client.get_margin_loan_orders(symbol="eosusdt")
+LogInfo.output_list(list_obj)
+
diff --git a/example/margin/post_cross_margin_create_loan_orders.py b/example/margin/post_cross_margin_create_loan_orders.py
new file mode 100644
index 0000000..741409c
--- /dev/null
+++ b/example/margin/post_cross_margin_create_loan_orders.py
@@ -0,0 +1,29 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+
+amount = 100
+currency = "usdt"
+
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+# order_id = margin_client.post_cross_margin_create_loan_orders(currency=currency, amount=amount)
+# LogInfo.output("step 1: create loan order {id}".format(id=order_id))
+
+# to check not clearing loan orders
+list_obj = margin_client.get_cross_margin_loan_orders(currency=currency, state=LoanOrderState.ACCRUAL)
+LogInfo.output("step 2: loaning order information ")
+LogInfo.output_list(list_obj)
+
+if list_obj and len(list_obj):
+ for loan_order in list_obj:
+ # pay attention to Scientific Notation
+ repay_amount = float(loan_order.loan_balance) + float(loan_order.interest_balance)
+ LogInfo.output("repay loan order {id}, repay amount : {amount}".format(id=loan_order.id, amount=repay_amount))
+ result = margin_client.post_cross_margin_loan_order_repay(order_id=loan_order.id, amount=repay_amount)
+ LogInfo.output("step 3: repay loan order {id}, status : {status}, repay amount : {amount}".format(id=loan_order.id, status=result, amount=repay_amount))
+
+list_obj = margin_client.get_cross_margin_loan_orders(currency=currency, state=LoanOrderState.ACCRUAL)
+LogInfo.output("step 4: loaning order history ")
+LogInfo.output_list(list_obj)
diff --git a/example/margin/post_cross_margin_loan_order_repay.py b/example/margin/post_cross_margin_loan_order_repay.py
new file mode 100644
index 0000000..5f0a1d3
--- /dev/null
+++ b/example/margin/post_cross_margin_loan_order_repay.py
@@ -0,0 +1,19 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+
+# to check not clearing loan orders
+list_obj = margin_client.get_cross_margin_loan_orders(currency="usdt", state=LoanOrderState.ACCRUAL)
+LogInfo.output_list(list_obj)
+
+if list_obj and len(list_obj):
+ for loan_order in list_obj:
+ repay_amount = float(loan_order.loan_balance) + float(loan_order.interest_balance)
+ LogInfo.output("repay loan order {id} and amount {amount}".format(id=loan_order.id, amount=repay_amount))
+ order_id = margin_client.post_cross_margin_loan_order_repay(order_id=loan_order.id, amount=repay_amount)
+
+# to check not clearing loan orders
+list_obj = margin_client.get_cross_margin_loan_orders(currency="usdt", state=LoanOrderState.ACCRUAL)
+LogInfo.output_list(list_obj)
\ No newline at end of file
diff --git a/example/margin/post_cross_margin_transfer.py b/example/margin/post_cross_margin_transfer.py
new file mode 100644
index 0000000..44ebdc4
--- /dev/null
+++ b/example/margin/post_cross_margin_transfer.py
@@ -0,0 +1,12 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+transfer_id = margin_client.post_cross_margin_transfer_in(currency="eos", amount=5)
+LogInfo.output(transfer_id)
+
+transfer_id = margin_client.post_cross_margin_transfer_out(currency="eos", amount=5)
+LogInfo.output(transfer_id)
+
+
diff --git a/example/margin/post_general_repay_loan.py b/example/margin/post_general_repay_loan.py
new file mode 100644
index 0000000..cf2f918
--- /dev/null
+++ b/example/margin/post_general_repay_loan.py
@@ -0,0 +1,8 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import LogInfo
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+
+list_result = margin_client.post_general_repay_loan(account_id=g_account_id, currency="usdt", amount=1)
+LogInfo.output_list(list_result)
diff --git a/example/margin/post_margin_create_order.py b/example/margin/post_margin_create_order.py
new file mode 100644
index 0000000..69c0efe
--- /dev/null
+++ b/example/margin/post_margin_create_order.py
@@ -0,0 +1,25 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+import time
+
+loan_amount = 100
+interest_amount = 0.004083
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+loan_id = margin_client.post_create_margin_order(symbol="eosusdt", currency="usdt", amount=loan_amount)
+LogInfo.output("step 1: loan id : {id}".format(id=loan_id))
+
+time.sleep(2)
+
+repay_id = margin_client.post_repay_margin_order(loan_id=loan_id, amount=loan_amount + interest_amount)
+LogInfo.output("step 2: repay id : {id}".format(id=repay_id))
+
+list_obj = margin_client.get_margin_loan_orders(symbol="eosusdt", states=LoanOrderState.ACCRUAL)
+LogInfo.output("step 3: loaning order information")
+LogInfo.output_list(list_obj)
+
+
+list_obj = margin_client.get_margin_loan_orders(symbol="eosusdt")
+LogInfo.output("step 4: loan order history")
+LogInfo.output_list(list_obj)
\ No newline at end of file
diff --git a/example/margin/post_margin_repay_order.py b/example/margin/post_margin_repay_order.py
new file mode 100644
index 0000000..386f29a
--- /dev/null
+++ b/example/margin/post_margin_repay_order.py
@@ -0,0 +1,8 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+transfer_id = margin_client.post_repay_margin_order(loan_id=7440184, amount=100.004083)
+LogInfo.output("transfer id : {id}".format(id=transfer_id))
+
diff --git a/example/margin/post_margin_transfer_in.py b/example/margin/post_margin_transfer_in.py
new file mode 100644
index 0000000..5b8f787
--- /dev/null
+++ b/example/margin/post_margin_transfer_in.py
@@ -0,0 +1,8 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+transfer_id = margin_client.post_transfer_in_margin(symbol="eosusdt", currency="usdt", amount=20)
+LogInfo.output("transfer id : {id}".format(id=transfer_id))
+
diff --git a/example/margin/post_margin_transfer_out.py b/example/margin/post_margin_transfer_out.py
new file mode 100644
index 0000000..6d23f81
--- /dev/null
+++ b/example/margin/post_margin_transfer_out.py
@@ -0,0 +1,7 @@
+from huobi.client.margin import MarginClient
+from huobi.constant import *
+from huobi.utils import *
+
+margin_client = MarginClient(api_key=g_api_key, secret_key=g_secret_key)
+transfer_id = margin_client.post_transfer_out_margin(symbol="eosusdt", currency="usdt", amount=20)
+LogInfo.output("transfer id : {id}".format(id=transfer_id))
diff --git a/example/market/get_candlestick.py b/example/market/get_candlestick.py
new file mode 100644
index 0000000..9b22f16
--- /dev/null
+++ b/example/market/get_candlestick.py
@@ -0,0 +1,26 @@
+from huobi.client.market import MarketClient
+from huobi.constant import *
+from huobi.utils import *
+
+market_client = MarketClient(init_log=True)
+interval = CandlestickInterval.MIN5
+symbol = "ethusdt"
+list_obj = market_client.get_candlestick(symbol, interval, 10)
+LogInfo.output("---- {interval} candlestick for {symbol} ----".format(interval=interval, symbol=symbol))
+LogInfo.output_list(list_obj)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/market/get_history_trade.py b/example/market/get_history_trade.py
new file mode 100644
index 0000000..e039c34
--- /dev/null
+++ b/example/market/get_history_trade.py
@@ -0,0 +1,5 @@
+from huobi.client.market import MarketClient
+from huobi.utils import *
+market_client = MarketClient()
+list_obj = market_client.get_history_trade("btcusdt", 6)
+LogInfo.output_list(list_obj)
diff --git a/example/market/get_market_detail.py b/example/market/get_market_detail.py
new file mode 100644
index 0000000..b7f1307
--- /dev/null
+++ b/example/market/get_market_detail.py
@@ -0,0 +1,8 @@
+from huobi.client.market import MarketClient
+
+market_client = MarketClient()
+obj = market_client.get_market_detail("btcusdt")
+obj.print_object()
+
+
+
diff --git a/example/market/get_market_detail_merged.py b/example/market/get_market_detail_merged.py
new file mode 100644
index 0000000..a247be0
--- /dev/null
+++ b/example/market/get_market_detail_merged.py
@@ -0,0 +1,9 @@
+from huobi.client.market import MarketClient
+from huobi.constant import *
+
+market_client = MarketClient()
+obj = market_client.get_market_detail_merged("btcusdt")
+obj.print_object()
+
+
+
diff --git a/example/market/get_market_tickers.py b/example/market/get_market_tickers.py
new file mode 100644
index 0000000..4270436
--- /dev/null
+++ b/example/market/get_market_tickers.py
@@ -0,0 +1,23 @@
+from huobi.client.market import MarketClient
+from huobi.constant import *
+from huobi.utils import *
+
+market_client = MarketClient(init_log=True)
+list_obj = market_client.get_market_tickers()
+LogInfo.output_list(list_obj)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/market/get_market_trade.py b/example/market/get_market_trade.py
new file mode 100644
index 0000000..6f4d89d
--- /dev/null
+++ b/example/market/get_market_trade.py
@@ -0,0 +1,18 @@
+from huobi.client.market import MarketClient
+from huobi.utils import *
+
+market_client = MarketClient()
+list_obj = market_client.get_market_trade(symbol="eosusdt")
+LogInfo.output_list(list_obj)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/market/get_pricedepth.py b/example/market/get_pricedepth.py
new file mode 100644
index 0000000..a15468c
--- /dev/null
+++ b/example/market/get_pricedepth.py
@@ -0,0 +1,21 @@
+
+from huobi.client.market import MarketClient
+from huobi.utils import *
+
+
+market_client = MarketClient()
+symbol = "btcusdt"
+depth_size = 6
+depth = market_client.get_pricedepth(symbol, DepthStep.STEP0, depth_size)
+LogInfo.output("---- Top {size} bids ----".format(size=len(depth.bids)))
+i = 0
+for entry in depth.bids:
+ i = i + 1
+ LogInfo.output(str(i) + ": price: " + str(entry.price) + ", amount: " + str(entry.amount))
+
+LogInfo.output("---- Top {size} asks ----".format(size=len(depth.asks)))
+
+i = 0
+for entry in depth.asks:
+ i = i + 1
+ LogInfo.output(str(i) + ": price: " + str(entry.price) + ", amount: " + str(entry.amount))
\ No newline at end of file
diff --git a/example/market/req_candlestick.py b/example/market/req_candlestick.py
new file mode 100644
index 0000000..bee2823
--- /dev/null
+++ b/example/market/req_candlestick.py
@@ -0,0 +1,16 @@
+from huobi.client.market import MarketClient
+from huobi.constant import *
+from huobi.exception.huobi_api_exception import HuobiApiException
+
+def callback(candlestick_req: 'CandlestickReq'):
+ candlestick_req.print_object()
+
+def error(e: 'HuobiApiException'):
+ print(e.error_code + e.error_message)
+
+sub_client = MarketClient(init_log=True)
+#sub_client.request_candlestick_event("btcusdt", CandlestickInterval.MIN1, callback, from_ts_second=None, end_ts_second=None, error_handler=None)
+#sub_client.request_candlestick_event("btcusdt", CandlestickInterval.MIN1, callback, from_ts_second=1571124360, end_ts_second=1571129820)
+#sub_client.request_candlestick_event("btcusdt", CandlestickInterval.MIN1, callback, from_ts_second=1569361140, end_ts_second=0)
+#sub_client.request_candlestick_event("btcusdt", CandlestickInterval.MIN1, callback, from_ts_second=1569379980)
+sub_client.req_candlestick("btcusdt", CandlestickInterval.MIN1, callback)
diff --git a/example/market/req_market_detail.py b/example/market/req_market_detail.py
new file mode 100644
index 0000000..bc63b99
--- /dev/null
+++ b/example/market/req_market_detail.py
@@ -0,0 +1,12 @@
+from huobi.client.market import MarketClient
+from huobi.model.market import *
+
+
+
+def callback(obj_event: 'MarketDetailReq'):
+ obj_event.print_object()
+ print()
+
+
+sub_client = MarketClient()
+sub_client.req_market_detail("btcusdt", callback)
diff --git a/example/market/req_mbp.py b/example/market/req_mbp.py
new file mode 100644
index 0000000..b2c3232
--- /dev/null
+++ b/example/market/req_mbp.py
@@ -0,0 +1,14 @@
+from huobi.client.market import MarketClient
+from huobi.constant import *
+
+
+def callback(mbp_event: 'MbpIncreaseEvent'):
+ mbp_event.print_object()
+
+
+def error(e: 'HuobiApiException'):
+ print(e.error_code + e.error_message)
+
+
+market_client = MarketClient(init_log=True)
+market_client.req_mbp("btcusdt", MbpLevel.MBP5, callback, error)
diff --git a/example/market/req_pricedepth.py b/example/market/req_pricedepth.py
new file mode 100644
index 0000000..3cc938a
--- /dev/null
+++ b/example/market/req_pricedepth.py
@@ -0,0 +1,15 @@
+
+from huobi.client.market import MarketClient
+from huobi.constant import DepthStep
+
+
+def callback(price_depth_req: 'PriceDepthReq'):
+ price_depth_req.print_object()
+
+
+def error(e: 'HuobiApiException'):
+ print(e.error_code + e.error_message)
+
+
+sub_client = MarketClient()
+sub_client.req_pricedepth("btcusdt", DepthStep.STEP0, callback, error)
diff --git a/example/market/req_trade_detail.py b/example/market/req_trade_detail.py
new file mode 100644
index 0000000..cc67fe9
--- /dev/null
+++ b/example/market/req_trade_detail.py
@@ -0,0 +1,15 @@
+from huobi.client.market import MarketClient
+
+
+
+def callback(trade_req: 'TradeDetailReq'):
+ print("---- trade_event: ----")
+ trade_req.print_object()
+ print()
+
+
+
+market_client = MarketClient()
+market_client.req_trade_detail("btcusdt,eosusdt", callback)
+
+
diff --git a/example/market/sub_candlestick.py b/example/market/sub_candlestick.py
new file mode 100644
index 0000000..732b44c
--- /dev/null
+++ b/example/market/sub_candlestick.py
@@ -0,0 +1,18 @@
+
+from huobi.client.market import MarketClient
+from huobi.constant import *
+from huobi.exception.huobi_api_exception import HuobiApiException
+from huobi.model.market.candlestick_event import CandlestickEvent
+
+
+def callback(candlestick_event: 'CandlestickEvent'):
+ candlestick_event.print_object()
+ print("\n")
+
+
+def error(e: 'HuobiApiException'):
+ print(e.error_code + e.error_message)
+
+market_client = MarketClient()
+market_client.sub_candlestick("btcusdt,ethusdt", CandlestickInterval.MIN1, callback, error)
+
diff --git a/example/market/sub_market_detail.py b/example/market/sub_market_detail.py
new file mode 100644
index 0000000..a567fba
--- /dev/null
+++ b/example/market/sub_market_detail.py
@@ -0,0 +1,11 @@
+from huobi.client.market import MarketClient
+from huobi.model.market import *
+
+
+def callback(obj_event: 'MarketDetailEvent'):
+ obj_event.print_object()
+ print()
+
+
+market_client = MarketClient()
+market_client.sub_market_detail("btcusdt", callback)
\ No newline at end of file
diff --git a/example/market/sub_mbp_full.py b/example/market/sub_mbp_full.py
new file mode 100644
index 0000000..e1cd3cb
--- /dev/null
+++ b/example/market/sub_mbp_full.py
@@ -0,0 +1,14 @@
+from huobi.client.market import MarketClient
+from huobi.constant import *
+
+
+def callback(mbp_event: 'MbpFullEvent'):
+ mbp_event.print_object()
+
+
+def error(e: 'HuobiApiException'):
+ print(e.error_code + e.error_message)
+
+
+market_client = MarketClient(init_log=True)
+market_client.sub_mbp_full("btcusdt,eosusdt", MbpLevel.MBP5, callback, error)
diff --git a/example/market/sub_mbp_increase.py b/example/market/sub_mbp_increase.py
new file mode 100644
index 0000000..044781e
--- /dev/null
+++ b/example/market/sub_mbp_increase.py
@@ -0,0 +1,14 @@
+from huobi.client.market import MarketClient
+from huobi.constant import *
+
+
+def callback(mbp_event: 'MbpIncreaseEvent'):
+ mbp_event.print_object()
+
+
+def error(e: 'HuobiApiException'):
+ print(e.error_code + e.error_message)
+
+
+market_client = MarketClient(init_log=True)
+market_client.sub_mbp_increase("btcusdt,eosusdt", MbpLevel.MBP5, callback, error)
diff --git a/example/market/sub_pricedepth.py b/example/market/sub_pricedepth.py
new file mode 100644
index 0000000..bca45d9
--- /dev/null
+++ b/example/market/sub_pricedepth.py
@@ -0,0 +1,18 @@
+
+from huobi.client.market import MarketClient
+from huobi.constant import *
+
+
+
+def callback(price_depth_event: 'PriceDepthEvent'):
+ price_depth_event.print_object()
+
+
+def error(e: 'HuobiApiException'):
+ print(e.error_code + e.error_message)
+
+
+market_client = MarketClient()
+market_client.sub_pricedepth("btcusdt", DepthStep.STEP0, callback, error)
+market_client.sub_pricedepth("eosusdt", DepthStep.STEP0, callback, error)
+market_client.sub_pricedepth("ethusdt", DepthStep.STEP0, callback, error)
diff --git a/example/market/sub_pricedepth_bbo.py b/example/market/sub_pricedepth_bbo.py
new file mode 100644
index 0000000..f1a9704
--- /dev/null
+++ b/example/market/sub_pricedepth_bbo.py
@@ -0,0 +1,15 @@
+
+from huobi.client.market import MarketClient
+
+
+def callback(price_depth_event: 'PriceDepthBboEvent'):
+ price_depth_event.print_object()
+ print()
+
+
+
+def error(e: 'HuobiApiException'):
+ print(e.error_code + e.error_message)
+
+market_client = MarketClient()
+market_client.sub_pricedepth_bbo("btcusdt", callback, error)
diff --git a/example/market/sub_trade_detail.py b/example/market/sub_trade_detail.py
new file mode 100644
index 0000000..a80e3a9
--- /dev/null
+++ b/example/market/sub_trade_detail.py
@@ -0,0 +1,13 @@
+from huobi.client.market import MarketClient
+
+
+def callback(trade_event: 'TradeDetailEvent'):
+ print("---- trade_event: ----")
+ trade_event.print_object()
+ print()
+
+
+
+market_client = MarketClient(init_log=True)
+market_client.sub_trade_detail("btcusdt,eosusdt", callback)
+
diff --git a/example/subuser/get_uid.py b/example/subuser/get_uid.py
new file mode 100644
index 0000000..9bea859
--- /dev/null
+++ b/example/subuser/get_uid.py
@@ -0,0 +1,10 @@
+from huobi.client.subuser import SubuserClient
+from huobi.constant import *
+from huobi.utils import *
+
+from example.api_key import *
+
+
+subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
+uid = subuser_client.get_uid()
+LogInfo.output(uid)
diff --git a/example/subuser/get_user_apikey_info.py b/example/subuser/get_user_apikey_info.py
new file mode 100644
index 0000000..870dd67
--- /dev/null
+++ b/example/subuser/get_user_apikey_info.py
@@ -0,0 +1,7 @@
+from huobi.client.subuser import SubuserClient
+from huobi.constant import *
+from huobi.utils import *
+
+subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
+apikey_info = subuser_client.get_user_apikey_info(122946475)
+LogInfo.output_list(apikey_info)
diff --git a/example/subuser/post_create_subuser.py b/example/subuser/post_create_subuser.py
new file mode 100644
index 0000000..49b3909
--- /dev/null
+++ b/example/subuser/post_create_subuser.py
@@ -0,0 +1,17 @@
+from huobi.client.subuser import SubuserClient
+from huobi.constant import *
+from huobi.utils import *
+import string
+import random
+
+subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
+userName = ''.join(random.choices(string.ascii_uppercase + string.digits, k=7))
+params = {"userList": [
+ {
+ "userName": userName,
+ "note": "huobi"
+ }
+]}
+
+userList = subuser_client.post_create_subuser(params)
+LogInfo.output_list(userList)
diff --git a/example/subuser/post_set_subuser_transferability.py b/example/subuser/post_set_subuser_transferability.py
new file mode 100644
index 0000000..39f6f7b
--- /dev/null
+++ b/example/subuser/post_set_subuser_transferability.py
@@ -0,0 +1,9 @@
+from huobi.client.subuser import SubuserClient
+from huobi.constant import *
+from huobi.utils import *
+
+subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
+sub_uids = '122946475'
+
+transferability_result = subuser_client.post_set_subuser_transferability(sub_uids, False)
+LogInfo.output_list(transferability_result)
diff --git a/example/subuser/post_subuser_apikey_deletion.py b/example/subuser/post_subuser_apikey_deletion.py
new file mode 100644
index 0000000..b493619
--- /dev/null
+++ b/example/subuser/post_subuser_apikey_deletion.py
@@ -0,0 +1,10 @@
+from huobi.client.subuser import SubuserClient
+from huobi.constant import *
+from huobi.utils import *
+
+subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
+sub_uid = '122946475'
+access_key = '7ab679d7-b9fee8ed-9cd4cd8a-bgbfh5tv3f'
+
+result = subuser_client.post_subuser_apikey_deletion(sub_uid, access_key)
+LogInfo.output(result)
diff --git a/example/subuser/post_subuser_apikey_generation.py b/example/subuser/post_subuser_apikey_generation.py
new file mode 100644
index 0000000..f2d65b2
--- /dev/null
+++ b/example/subuser/post_subuser_apikey_generation.py
@@ -0,0 +1,13 @@
+from huobi.client.subuser import SubuserClient
+from huobi.constant import *
+
+subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
+
+otp_token = '746316'
+sub_uid = 122946475
+note = "huobi_subuser"
+permission = 'readOnly'
+# ip_addresses = ''
+
+result = subuser_client.post_subuser_apikey_generate(otp_token, sub_uid, note, permission)
+result.print_object()
diff --git a/example/subuser/post_subuser_apikey_modification.py b/example/subuser/post_subuser_apikey_modification.py
new file mode 100644
index 0000000..63a1c51
--- /dev/null
+++ b/example/subuser/post_subuser_apikey_modification.py
@@ -0,0 +1,12 @@
+from huobi.client.subuser import SubuserClient
+from huobi.constant import *
+
+subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
+
+subUid = 122946475
+access_key = "abc"
+note = "test"
+permission = 'readOnly,trade'
+
+result = subuser_client.post_subuser_apikey_modification(subUid, access_key, permission=permission, note=note)
+result.print_object()
diff --git a/example/subuser/post_trade_market.py b/example/subuser/post_trade_market.py
new file mode 100644
index 0000000..dd0df19
--- /dev/null
+++ b/example/subuser/post_trade_market.py
@@ -0,0 +1,12 @@
+from huobi.client.subuser import SubuserClient
+from huobi.constant import *
+from huobi.utils import *
+
+subuser_client = SubuserClient(api_key=g_api_key, secret_key=g_secret_key)
+
+subUids = '159284259'
+accountType = SubuserTradePrivilegeType.MARGIN
+activation = SubUserTradeStatus.DEACTIVATED
+
+subUserList = subuser_client.post_set_tradable_market(subUids, accountType, activation)
+LogInfo.output_list(subUserList)
diff --git a/example/trade/get_feerate.py b/example/trade/get_feerate.py
new file mode 100644
index 0000000..d605e6e
--- /dev/null
+++ b/example/trade/get_feerate.py
@@ -0,0 +1,10 @@
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+from example.api_key import *
+
+
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+list_obj = trade_client.get_feerate(symbols="htusdt,btcusdt,eosusdt")
+LogInfo.output_list(list_obj)
\ No newline at end of file
diff --git a/example/trade/get_history_orders_in_48hours.py b/example/trade/get_history_orders_in_48hours.py
new file mode 100644
index 0000000..248e65a
--- /dev/null
+++ b/example/trade/get_history_orders_in_48hours.py
@@ -0,0 +1,26 @@
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+from example.api_key import *
+
+symbol_test_list = ["linkusdt"]
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+for symbol_test in symbol_test_list:
+ list_obj = trade_client.get_history_orders(symbol=symbol_test, start_time=None, end_time=None, size=20, direct=None)
+ LogInfo.output_list(list_obj)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/trade/get_matchresult.py b/example/trade/get_matchresult.py
new file mode 100644
index 0000000..ece70cf
--- /dev/null
+++ b/example/trade/get_matchresult.py
@@ -0,0 +1,11 @@
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+list_obj = trade_client.get_match_result(symbol="trxusdt", size=5, direct=QueryDirection.NEXT)
+LogInfo.output_list(list_obj)
+
+list_obj = trade_client.get_match_result(symbol="eosusdt", size=5)
+LogInfo.output_list(list_obj)
\ No newline at end of file
diff --git a/example/trade/get_matchresult_by_order_id.py b/example/trade/get_matchresult_by_order_id.py
new file mode 100644
index 0000000..843680f
--- /dev/null
+++ b/example/trade/get_matchresult_by_order_id.py
@@ -0,0 +1,11 @@
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+
+
+order_id_test = 87939085540
+
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+list_obj = trade_client.get_match_results_by_order_id(order_id=order_id_test)
+LogInfo.output_list(list_obj)
\ No newline at end of file
diff --git a/example/trade/get_open_orders.py b/example/trade/get_open_orders.py
new file mode 100644
index 0000000..246dd97
--- /dev/null
+++ b/example/trade/get_open_orders.py
@@ -0,0 +1,25 @@
+from huobi.client.account import AccountClient
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+from example.api_key import *
+
+
+symbol = "btcusdt"
+
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+account_client = AccountClient(api_key=g_api_key,secret_key=g_secret_key)
+
+account_spot = account_client.get_account_by_type_and_symbol(account_type=AccountType.SPOT, symbol=None)
+account_id_test = account_spot.id
+
+direct_tmp = QueryDirection.NEXT
+LogInfo.output("==============test case 1 for {direct}===============".format(direct=direct_tmp))
+list_obj = trade_client.get_open_orders(symbol=symbol, account_id=account_id_test, direct=direct_tmp)
+LogInfo.output_list(list_obj)
+
+direct_tmp = QueryDirection.PREV
+LogInfo.output("==============test case 2 for {direct}===============".format(direct=direct_tmp))
+list_obj = trade_client.get_open_orders(symbol=symbol, account_id=account_id_test, direct=direct_tmp)
+LogInfo.output_list(list_obj)
diff --git a/example/trade/get_order.py b/example/trade/get_order.py
new file mode 100644
index 0000000..fedfe56
--- /dev/null
+++ b/example/trade/get_order.py
@@ -0,0 +1,10 @@
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+order_id = 25943298415466
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+orderObj = trade_client.get_order(order_id=order_id)
+LogInfo.output("======= get order by order id : {order_id} =======".format(order_id=order_id))
+orderObj.print_object()
+
diff --git a/example/trade/get_order_by_client_order_id.py b/example/trade/get_order_by_client_order_id.py
new file mode 100644
index 0000000..9c5bdda
--- /dev/null
+++ b/example/trade/get_order_by_client_order_id.py
@@ -0,0 +1,12 @@
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+client_order_id_test = "xxxxxx" # unique id in 24hours
+
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+orderObj = trade_client.get_order_by_client_order_id(client_order_id=client_order_id_test)
+LogInfo.output("======= get order by client order id : {client_id} =======".format(client_id=client_order_id_test))
+orderObj.print_object()
+
+
diff --git a/example/trade/get_orders.py b/example/trade/get_orders.py
new file mode 100644
index 0000000..7ddd666
--- /dev/null
+++ b/example/trade/get_orders.py
@@ -0,0 +1,27 @@
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+from example.api_key import *
+
+symbol = "linkusdt"
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+list_obj = trade_client.get_orders(symbol=symbol, order_state=OrderState.FILLED,
+ order_type=OrderType.BUY_LIMIT, start_date=None, end_date=None,
+ start_id=None, size=None, direct=QueryDirection.PREV)
+
+LogInfo.output("===== step 1 ==== {symbol} {count} orders found".format(symbol=symbol, count=len(list_obj)))
+LogInfo.output_list(list_obj)
+
+symbol = "linkusdt"
+list_obj = trade_client.get_orders(symbol=symbol, order_state=OrderState.CANCELED,
+ order_type=OrderType.BUY_LIMIT, start_date="2021-01-21", end_date=None,
+ start_id=None, size=None, direct=QueryDirection.PREV)
+LogInfo.output("===== step 2 ==== {symbol} {count} canceled buy limit orders found".format(symbol=symbol, count=len(list_obj)))
+LogInfo.output_list(list_obj)
+
+list_obj = trade_client.get_orders(symbol=symbol, order_state=OrderState.FILLED,
+ order_type=None, start_date=None, end_date=None,
+ start_id=None, size=None, direct=QueryDirection.PREV)
+LogInfo.output("===== step 3 ==== {symbol} {count} filled orders found".format(symbol=symbol, count=len(list_obj)))
+LogInfo.output_list(list_obj)
diff --git a/example/trade/get_transact_feerate.py b/example/trade/get_transact_feerate.py
new file mode 100644
index 0000000..6563a7e
--- /dev/null
+++ b/example/trade/get_transact_feerate.py
@@ -0,0 +1,9 @@
+
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+list_obj = trade_client.get_transact_feerate(symbols="htusdt,btcusdt,eosusdt")
+LogInfo.output_list(list_obj)
\ No newline at end of file
diff --git a/example/trade/post_batch_cancel_open_order.py b/example/trade/post_batch_cancel_open_order.py
new file mode 100644
index 0000000..464a703
--- /dev/null
+++ b/example/trade/post_batch_cancel_open_order.py
@@ -0,0 +1,8 @@
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+
+
+# cancel all the open orders under account
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+result = trade_client.cancel_open_orders(account_id=g_account_id)
+result.print_object()
diff --git a/example/trade/post_batch_cancel_order.py b/example/trade/post_batch_cancel_order.py
new file mode 100644
index 0000000..ea2d982
--- /dev/null
+++ b/example/trade/post_batch_cancel_order.py
@@ -0,0 +1,21 @@
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+
+trade_client = TradeClient(api_key=g_api_key, secret_key=g_secret_key)
+symbol_test = "eosusdt"
+
+i = 0
+n = 3
+order_id_list = []
+while(i list:
+ from huobi.service.account.get_balance import GetBalanceService
+ """
+ Get the balance of a all accounts.
+
+ :return: The information of all account balance.
+ """
+ server_url = get_default_server_url(self.__kwargs.get("url"))
+ tasks = []
+ account_obj_map = {}
+ accounts = self.get_accounts()
+ account_balance_list = []
+ account_balance_json_map = {}
+ for account_item in accounts:
+ account_obj_map[account_item.id] = account_item
+ balance_params = {"account-id": account_item.id}
+ balance_request = GetBalanceService(balance_params).get_request(**self.__kwargs)
+ balance_url = server_url + balance_request.url
+ tasks.append(asyncio.ensure_future(
+ self.async_get_account_balance(balance_url, account_item.id, account_balance_json_map)))
+
+ loop = asyncio.get_event_loop()
+ try:
+ loop.run_until_complete(asyncio.wait(tasks))
+ except Exception as ee:
+ print(ee)
+ finally:
+ # loop.close() #for thread safe, the event loop can't be closed
+ pass
+
+ for account_id, account_balance_json in account_balance_json_map.items():
+ account_balance = AccountBalance.json_parse(account_balance_json.get("data", {}))
+ account_obj_tmp = account_obj_map.get(account_id, None)
+ account_balance.subtype = None if account_obj_tmp is None else account_obj_tmp.subtype
+ account_balance_list.append(account_balance)
+
+ del account_balance_json_map
+ del tasks
+ return account_balance_list
+
+ def get_account_balance_by_subuid(self, sub_uid):
+ """
+ Get account balance of a sub-account.
+
+ :param sub_uid: the specified sub account id to get balance for.
+ :return: the balance of a sub-account specified by sub-account uid.
+ """
+ check_should_not_none(sub_uid, "sub-uid")
+ params = {
+ "sub-uid": sub_uid
+ }
+ from huobi.service.account.get_account_balance_by_subuid import GetAccountBalanceBySubUidService
+ return GetAccountBalanceBySubUidService(params).request(**self.__kwargs)
+
+ def get_aggregated_subuser_balance(self):
+ """
+ Get the aggregated balance of all sub-accounts of the current user.
+
+ :return: The balance of all the sub-account aggregated.
+ """
+ params = {}
+ from huobi.service.account.get_aggregate_subuser_balance import GetAggregateSubUserBalanceService
+ return GetAggregateSubUserBalanceService(params).request(**self.__kwargs)
+
+ def transfer_between_parent_and_subuser(self, sub_uid: 'int', currency: 'str', amount: 'float',
+ transfer_type: 'TransferMasterType'):
+ """
+ Transfer Asset between Parent and Sub Account.
+
+ :param sub_uid: The target sub account uid to transfer to or from. (mandatory)
+ :param currency: The crypto currency to transfer. (mandatory)
+ :param amount: The amount of asset to transfer. (mandatory)
+ :param transfer_type: The type of transfer, see {@link TransferMasterType} (mandatory)
+ :return: The order id.
+ """
+ check_currency(currency)
+ check_should_not_none(sub_uid, "sub-uid")
+ check_should_not_none(amount, "amount")
+ check_should_not_none(transfer_type, "type")
+
+ params = {
+ "sub-uid": sub_uid,
+ "currency": currency,
+ "amount": amount,
+ "type": transfer_type
+ }
+ from huobi.service.account.post_subaccount_transfer import PostSubaccountTransferService
+ return PostSubaccountTransferService(params).request(**self.__kwargs)
+
+ def sub_account_update(self, mode: 'AccountBalanceMode', callback, error_handler=None):
+ """
+ Subscribe accounts update
+
+ :param mode: subscribe mode
+ "0" : for balance
+ "1" : for available and balance
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(price_depth_event: 'PriceDepthEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+
+ :return: No return
+ """
+
+ check_should_not_none(callback, "callback")
+ if str(mode) == AccountBalanceMode.TOTAL:
+ mode = AccountBalanceMode.TOTAL
+ else:
+ mode = AccountBalanceMode.BALANCE
+
+ params = {
+ "mode": mode,
+ }
+
+ from huobi.service.account.sub_account_update_v2 import SubAccountUpdateV2Service
+ SubAccountUpdateV2Service(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def req_account_balance(self, callback, client_req_id=None, error_handler=None):
+ """
+ Subscribe account changing event. If the balance is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param client_req_id: client request ID
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(account_event: 'AccountEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+
+ check_should_not_none(callback, "callback")
+ params = {
+ "client_req_id": client_req_id
+ }
+
+ from huobi.service.account.req_account_balance import ReqAccountBalanceService
+ ReqAccountBalanceService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def transfer_between_futures_and_pro(self, currency: 'str', amount: 'float',
+ transfer_type: 'TransferFuturesPro') -> int:
+ """
+ Transfer Asset between Futures and Contract.
+
+ :param currency: The crypto currency to transfer. (mandatory)
+ :param amount: The amount of asset to transfer. (mandatory)
+ :param transfer_type: The type of transfer, need be "futures-to-pro" or "pro-to-futures" (mandatory)
+ :return: The order id.
+ """
+
+ check_currency(currency)
+ check_should_not_none(currency, "currency")
+ check_should_not_none(amount, "amount")
+ check_should_not_none(transfer_type, "transfer_type")
+ params = {
+ "currency": currency,
+ "amount": amount,
+ "type": transfer_type
+ }
+
+ from huobi.service.account.post_futures_and_pro_transfer import PostTransferBetweenFuturesAndProService
+ return PostTransferBetweenFuturesAndProService(params).request(**self.__kwargs)
+
+ def get_account_balance_by_subuid(self, sub_uid):
+ """
+ Get account balance of a sub-account.
+
+ :param sub_uid: the specified sub account id to get balance for.
+ :return: the balance of a sub-account specified by sub-account uid.
+ """
+ check_should_not_none(sub_uid, "sub-uid")
+ params = {
+ "sub-uid": sub_uid
+ }
+ from huobi.service.account.get_account_balance_by_subuid import GetAccountBalanceBySubUidService
+ return GetAccountBalanceBySubUidService(params).request(**self.__kwargs)
+
+ def get_account_history(self, account_id: 'int', currency: 'str' = None,
+ transact_types: 'str' = None, start_time: 'int' = None, end_time: 'int' = None,
+ sort: 'str' = None, size: 'int' = None):
+ """
+ get account change record
+ :param account_id: account id (mandatory)
+ :param currency: currency as "btc,eth" (optional)
+ :param transact_types: see AccountTransactType, the value can be "trade" (交易),"etf"(ETF申购), "transact-fee"(交易手续费), "deduction"(手续费抵扣), "transfer"(划转), "credit"(借币), "liquidation"(清仓), "interest"(币息), "deposit"(充币),"withdraw"(提币), "withdraw-fee"(提币手续费), "exchange"(兑换), "other-types"(其他) (optional)
+ :param start_time&end_time: for time range to search (optional)
+ :param sort: see SortDesc, "asc" or "desc" (optional)
+ :param size: page size (optional)
+
+ :return: account change record list.
+ """
+ check_should_not_none(account_id, "account-id")
+ params = {
+ "account-id": account_id,
+ "currency": currency,
+ "transact-types": transact_types,
+ "start-time": start_time,
+ "end-time": end_time,
+ "sort": sort,
+ "size": size
+ }
+ from huobi.service.account.get_account_history import GetAccountHistoryService
+ return GetAccountHistoryService(params).request(**self.__kwargs)
+
+ def post_sub_uid_management(self, sub_uid: 'int', action: 'str'):
+ """
+ use to freeze or unfreeze the sub uid
+
+ :return: user and status.
+ """
+
+ check_should_not_none(sub_uid, "subUid")
+ check_should_not_none(action, "action")
+
+ params = {
+ "subUid": sub_uid,
+ "action": action
+ }
+ from huobi.service.account.post_sub_uid_management import PostSubUidManagementService
+ return PostSubUidManagementService(params).request(**self.__kwargs)
+
+ def get_account_ledger(self, account_id: 'int', currency: 'str' = None, transact_types: 'str' = None,
+ start_time: 'int' = None, end_time: 'int' = None, sort: 'str' = None, limit: 'int' = None,
+ from_id: 'int' = None) -> list:
+ """
+ get account ledger
+ :param account_id: account id (mandatory)
+ :param currency: currency as "btc,eth" (optional)
+ :param transact_types: see AccountTransactType, the value can be "trade" (交易),"etf"(ETF申购), "transact-fee"(交易手续费), "deduction"(手续费抵扣), "transfer"(划转), "credit"(借币), "liquidation"(清仓), "interest"(币息), "deposit"(充币),"withdraw"(提币), "withdraw-fee"(提币手续费), "exchange"(兑换), "other-types"(其他) (optional)
+ :param start_time&end_time: for time range to search (optional)
+ :param sort: see SortDesc, "asc" or "desc" (optional)
+ :param size: page size (optional)
+ :return: account ledger list.
+ """
+
+ check_should_not_none(account_id, "accountId")
+
+ params = {
+ "accountId": account_id,
+ "currency": currency,
+ "transactTypes": transact_types,
+ "startTime": start_time,
+ "endTime": end_time,
+ "sort": sort,
+ "limit": limit,
+ "fromId": from_id
+ }
+ from huobi.service.account.get_account_ledger import GetAccountLedgerService
+ return GetAccountLedgerService(params).request(**self.__kwargs)
+
+ def post_account_transfer(self, from_user: 'int', from_account_type: 'str', from_account: 'int', to_user: 'int',
+ to_account_type: 'str', to_account: 'int', currency: 'str', amount: 'str'):
+ check_should_not_none(from_user, "from-user")
+ check_should_not_none(from_account_type, "from-account-type")
+ check_should_not_none(from_account, "from_account")
+ check_should_not_none(to_user, "to-user")
+ check_should_not_none(to_account, "to-account")
+ check_should_not_none(to_account_type, "to-account")
+ check_should_not_none(currency, "currency")
+
+ check_in_list(from_account_type, [AccountType.SPOT], "from_account_type")
+ check_in_list(to_account_type, [AccountType.SPOT], "to_account_type")
+
+ params = {
+ "from-user": from_user,
+ "from-account-type": from_account_type,
+ "from-account": from_account,
+ "to-user": to_user,
+ "to-account-type": to_account_type,
+ "to-account": to_account,
+ "currency": currency,
+ "amount": amount
+ }
+ from huobi.service.account.post_account_transfer import PostAccountTransferService
+ return PostAccountTransferService(params).request(**self.__kwargs)
+
+ def get_account_asset_valuation(self, account_type, valuation_currency: 'str' = None, sub_uid: 'str' = None):
+ check_should_not_none(account_type, "account-type")
+
+ params = {
+ "accountType": account_type,
+ "valuationCurrency": valuation_currency.upper(),
+ "subUid": sub_uid
+ }
+ from huobi.service.account.get_account_asset_valuation import GetAccountAssetValuationService
+ return GetAccountAssetValuationService(params).request(**self.__kwargs)
+
+ def get_account_point(self, sub_uid: 'str' = None):
+ params = {
+ "subUid": sub_uid
+ }
+
+ from huobi.service.account.get_account_point import GetAccountPointService
+ return GetAccountPointService(params).request(**self.__kwargs)
+
+ def post_point_transfer(self, from_uid: 'str', to_uid: 'str', group_id: 'str', amount: 'str'):
+
+ params = {
+ "fromUid": from_uid,
+ "toUid": to_uid,
+ "groupId": group_id,
+ "amount": amount
+ }
+
+ from huobi.service.account.post_point_transfer import PostPointTransferService
+ return PostPointTransferService(params).request(**self.__kwargs)
diff --git a/huobi/client/algo.py b/huobi/client/algo.py
new file mode 100644
index 0000000..b684096
--- /dev/null
+++ b/huobi/client/algo.py
@@ -0,0 +1,127 @@
+from huobi.model.algo import *
+from huobi.utils.input_checker import *
+
+
+class AlgoClient(object):
+
+ def __init__(self, **kwargs):
+ """
+ Create the request client instance.
+ :param kwargs: The option of request connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: The URL name like "https://api.huobi.pro".
+ init_log: to init logger
+ """
+ self.__kwargs = kwargs
+
+ def create_order(self, account_id: 'int', symbol: 'str', order_side: 'OrderSide', order_type: 'OrderType',
+ client_order_id: 'str', stop_price: 'str', order_price: 'str' = None, order_size: 'str' = None,
+ order_value: 'str' = None, time_in_force: 'str' = None, trailing_rate: 'str' = None) -> int:
+ """
+ Make an algo order in huobi.
+ :param account_id: Account id. (mandatory)
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param order_side: the Order side, possible values: buy,sell. (mandatory)
+ :param order_type: The order type, possible values: limit, market. (mandatory)
+ :param stop_price: The stop price. (mandatory)
+ :param order_price: The limit price of limit order, only needed for limit order. (mandatory for buy-limit, sell-limit, buy-limit-maker and sell-limit-maker)
+ :param order_size: The amount of market order only
+ :param order_value: for market buy order only
+ :param stop_price: Price for auto sell to get the max benefit
+ :param time_in_force: gtc(invalid for orderType=market), boc(invalid orderType=market),ioc,fok(invalid for orderType=market)
+ :param trailing_rate: for trailing orders only
+ :param client_order_id: unique Id which is user defined and must be unique in recent 24 hours
+ """
+
+ params = self.create_order_param_check(symbol, account_id, order_side, order_type, stop_price, order_price,
+ order_size, order_value, time_in_force, trailing_rate, client_order_id)
+ from huobi.service.algo.post_create_order import PostCreateOrderService
+ return PostCreateOrderService(params).request(**self.__kwargs)
+
+ def cancel_orders(self, client_order_ids) -> CancelOrderResult:
+ check_should_not_none(client_order_ids, "clientOrderIds")
+
+ params = {
+ "clientOrderIds": client_order_ids
+ }
+ from huobi.service.algo.post_cancel_orders import PostCancelOrderService
+ return PostCancelOrderService(params).request(**self.__kwargs)
+
+ def get_open_orders(self, account_id: 'str' = None, symbol: 'str' = None, order_side: 'OrderSide' = None,
+ order_type: 'AlgoOrderType' = None, sort: 'SortDesc' = None, limit: 'int' = 100,
+ from_id: 'int' = None):
+
+ params = {
+ "accountId": account_id,
+ "symbol": symbol,
+ "orderSide": order_side,
+ "orderType": order_type,
+ "sort": sort,
+ "limit": limit,
+ "fromId": from_id
+ }
+ from huobi.service.algo.get_open_orders import GetOpenOrdersService
+ return GetOpenOrdersService(params).request(**self.__kwargs)
+
+ def get_order_history(self, symbol: 'str', order_status: 'AlgoOrderStatus', account_id: 'str' = None,
+ order_side: 'OrderSide' = None, order_type: 'AlgoOrderType' = None, start_time: 'int' = None,
+ end_time: 'int' = None, sort: 'SortDesc' = SortDesc.DESC, limit: 'int' = 100,
+ from_id: 'int' = None):
+
+ params = {
+ "symbol": symbol,
+ "accountId": account_id,
+ "orderSide": order_side,
+ "orderType": order_type,
+ "orderStatus": order_status,
+ "startTime": start_time,
+ "endTime": end_time,
+ "sort": sort,
+ "limit": limit,
+ "fromId": from_id
+ }
+ from huobi.service.algo.get_order_history import GetOrderHistoryService
+ return GetOrderHistoryService(params).request(**self.__kwargs)
+
+ def get_order(self, client_order_id: 'str'):
+ params = {
+ "clientOrderId": client_order_id
+ }
+ from huobi.service.algo.get_order_by_cid import GetOrderByClientOrderIdService
+ return GetOrderByClientOrderIdService(params).request(**self.__kwargs)
+
+ def create_order_param_check(self, symbol, account_id, order_side, order_type, stop_price, order_price,
+ order_size, order_value, time_in_force, trailing_rate, client_order_id):
+ check_symbol(symbol)
+ check_should_not_none(account_id, "accountId")
+ check_should_not_none(order_type, "orderType")
+ check_should_not_none(order_side, "orderSide")
+
+ if order_type == OrderType.SELL_LIMIT \
+ or order_type == OrderType.BUY_LIMIT \
+ or order_type == OrderType.BUY_LIMIT_MAKER \
+ or order_type == OrderType.SELL_LIMIT_MAKER:
+ check_should_not_none(order_price, "orderPrice")
+
+ if time_in_force is not None:
+ check_time_in_force(time_in_force)
+
+ if order_type in [OrderType.SELL_MARKET, OrderType.BUY_MARKET]:
+ order_price = None
+
+ params = {
+ "accountId": account_id,
+ "symbol": symbol,
+ "orderPrice": order_price,
+ "orderSide": order_side,
+ "orderSize": order_size,
+ "orderValue": order_value,
+ "timeInForce": time_in_force,
+ "orderType": order_type,
+ "clientOrderId": client_order_id,
+ "stopPrice": stop_price,
+ "trailingRate": trailing_rate
+ }
+
+ return params
diff --git a/huobi/client/etf.py b/huobi/client/etf.py
new file mode 100644
index 0000000..3f1668c
--- /dev/null
+++ b/huobi/client/etf.py
@@ -0,0 +1,93 @@
+from huobi.constant import *
+from huobi.model.etf import *
+from huobi.utils import *
+
+
+class EtfClient(object):
+
+ def __init__(self, **kwargs):
+ """
+ Create the request client instance.
+ :param kwargs: The option of request connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: The URL name like "https://api.huobi.pro".
+ init_log: to init logger
+ """
+ self.__kwargs = kwargs
+
+ def get_etf_swap_config(self, etf_name: 'str') -> EtfSwapConfig:
+ """
+ Get the basic information of ETF creation and redemption, as well as ETF constituents,
+ including max amount of creation, min amount of creation, max amount of redemption, min amount
+ of redemption, creation fee rate, redemption fee rate, eft create/redeem status.
+
+ :param etf_symbol: The symbol, currently only support hb10. (mandatory)
+ :return: The etf configuration information.
+ """
+ check_symbol(etf_name)
+ params={
+ "etf_name":etf_name
+ }
+
+ from huobi.service.etf.get_etf_swap_config import GetEtfSwapConfigService
+ return GetEtfSwapConfigService(params).request(**self.__kwargs)
+
+ def get_etf_swap_list(self, etf_name: 'str', offset: 'int', size: 'int') -> list:
+ """
+ Get past creation and redemption.(up to 100 records)
+
+ :param etf_symbol: The symbol, currently only support hb10. (mandatory)
+ :param offset: The offset of the records, set to 0 for the latest records. (mandatory)
+ :param size: The number of records to return, the range is [1, 100]. (mandatory)
+ :return: The swap history.
+ """
+ check_symbol(etf_name)
+ params={
+ "etf_name":etf_name,
+ "offset" : offset,
+ "limit" : size
+ }
+
+ from huobi.service.etf.get_etf_swap_list import GetEtfSwapListService
+ return GetEtfSwapListService(params).request(**self.__kwargs)
+
+ def post_etf_swap_in(self, etf_name: 'str', amount: 'int') -> None:
+ """
+ Order creation or redemption of ETF.
+
+ :param etf_name: The symbol, currently only support hb10. (mandatory)
+ :param amount: The amount to create or redemption. (mandatory)
+ :return: No return
+ """
+ check_symbol(etf_name)
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "etf_name" : etf_name,
+ "amount" : amount
+ }
+
+ from huobi.service.etf.post_etf_swap_in import PostEftSwapInService
+ return PostEftSwapInService(params).request(**self.__kwargs)
+
+ def post_etf_swap_out(self, etf_name: 'str', amount: 'int') -> None:
+ """
+ Order creation or redemption of ETF.
+
+ :param etf_name: The symbol, currently only support hb10. (mandatory)
+ :param amount: The amount to create or redemption. (mandatory)
+ :return: No return
+ """
+
+ check_symbol(etf_name)
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "etf_name": etf_name,
+ "amount": amount
+ }
+
+ from huobi.service.etf.post_etf_swap_out import PostEtfSwapOutService
+ return PostEtfSwapOutService(params).request(**self.__kwargs)
+
diff --git a/huobi/client/generic.py b/huobi/client/generic.py
new file mode 100644
index 0000000..ddc0ce1
--- /dev/null
+++ b/huobi/client/generic.py
@@ -0,0 +1,102 @@
+from huobi.connection.impl.restapi_request import RestApiRequest
+from huobi.constant import *
+from huobi.model.generic import *
+
+
+class GenericClient(object):
+
+ def __init__(self, **kwargs):
+ """
+ Create the request client instance.
+ :param kwargs: The option of request connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: The URL name like "https://api.huobi.pro".
+ init_log: to init logger
+ """
+ self.__kwargs = kwargs
+
+ def get_exchange_timestamp(self) -> int:
+ """
+ Get the timestamp from Huobi server. The timestamp is the Unix timestamp in millisecond.
+ The count shows how many milliseconds passed from Jan 1st 1970, 00:00:00.000 at UTC.
+ e.g. 1546300800000 is Thu, 1st Jan 2019 00:00:00.000 UTC.
+
+ :return: The timestamp in UTC
+ """
+
+ params = {}
+
+ from huobi.service.generic.get_exchange_timestamp import GetExchangeTimestampService
+ return GetExchangeTimestampService(params).request(**self.__kwargs)
+
+ def get_exchange_currencies(self) -> list():
+ """
+ Get all the trading assets and currencies supported in huobi.
+ The information of trading instrument, including base currency, quote precision, etc.
+
+ :return: The information of trading currencies.
+ """
+
+ params = {}
+
+ from huobi.service.generic.get_exchange_currencies import GetExchangeCurrenciesService
+ return GetExchangeCurrenciesService(params).request(**self.__kwargs)
+
+ def get_exchange_symbols(self) -> list():
+ """
+ Get all the trading assets and currencies supported in huobi.
+ The information of trading instrument etc.
+
+ :return: The information of trading instrument.
+ """
+
+ params = {}
+
+ from huobi.service.generic.get_exchange_symbols import GetExchangeSymbolsService
+ return GetExchangeSymbolsService(params).request(**self.__kwargs)
+
+ def get_exchange_info(self) -> ExchangeInfo:
+ """
+ Get all the trading assets and currencies supported in huobi.
+ The information of trading instrument, including base currency, quote precision, etc.
+
+ :return: The information of trading instrument and currencies.
+ """
+
+ ret = ExchangeInfo()
+ ret.symbol_list = self.get_exchange_symbols()
+ ret.currencies = self.get_exchange_currencies()
+ return ret
+
+ def get_reference_currencies(self, currency: 'str' = None, is_authorized_user: 'bool' = None) -> list:
+ """
+ Get all the trading assets and currencies supported in huobi.
+ The information of trading instrument, including base currency, quote precision, etc.
+
+ :param currency: btc, ltc, bch, eth, etc ...(available currencies in Huobi Global)
+ :param is_authorized_user: is Authorized user? True or False
+ :return: The information of trading instrument and currencies.
+ """
+
+ params = {
+ "currency": currency,
+ "authorizedUser": is_authorized_user
+ }
+
+ from huobi.service.generic.get_reference_currencies import GetReferenceCurrenciesService
+ return GetReferenceCurrenciesService(params).request(**self.__kwargs)
+
+ def get_system_status(self) -> str:
+ """
+ get system status
+
+ :return: system status.
+ """
+
+ from huobi.service.generic.get_system_status import GetSystemStatusService
+ return GetSystemStatusService({}).request(**self.__kwargs)
+
+ def get_market_status(self):
+ from huobi.service.generic.get_market_status import GetMarketStatusService
+ return GetMarketStatusService({}).request(**self.__kwargs)
diff --git a/huobi/client/linear_swap.py b/huobi/client/linear_swap.py
new file mode 100644
index 0000000..5e586c1
--- /dev/null
+++ b/huobi/client/linear_swap.py
@@ -0,0 +1,540 @@
+from huobi.constant import *
+from huobi.model.trade import *
+from huobi.utils.input_checker import *
+
+
+class TradeClient(object):
+
+ def __init__(self, **kwargs):
+ """
+ Create the request client instance.
+ :param kwargs: The option of request connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: The URL name like "https://api.huobi.pro".
+ init_log: to init logger
+ """
+ self.__kwargs = kwargs
+
+ def get_feerate(self, symbols: 'str') -> list:
+ """
+ Get the candlestick/kline for the specified symbol. The data number is 150 as default.
+
+ :param symbol: The symbol, like "btcusdt". To query hb10, put "hb10" at here. (mandatory)
+ :param interval: The candlestick/kline interval, MIN1, MIN5, DAY1 etc. (mandatory)
+ :param size: The start time of of requested candlestick/kline data. (optional)
+ :param start_time: The start time of of requested candlestick/kline data. (optional)
+ :param end_time: The end time of of requested candlestick/kline data. (optional)
+ :return: The list of candlestick/kline data.
+ """
+ check_symbol(symbols)
+
+ params = {
+ "symbols": symbols
+ }
+
+ from huobi.service.trade.get_feerate import GetFeeRateService
+ return GetFeeRateService(params).request(**self.__kwargs)
+
+ def get_transact_feerate(self, symbols: 'str') -> list:
+ """
+ The request of get transact fee rate list.
+
+ :param symbols: The symbol, like "btcusdt,htusdt". (mandatory)
+ :return: The transact fee rate list.
+ """
+ check_symbol(symbols)
+
+ params = {
+ "symbols": symbols
+ }
+
+ from huobi.service.trade.get_transact_feerate import GetTransactFeeRateService
+ return GetTransactFeeRateService(params).request(**self.__kwargs)
+
+ def sub_order_update(self, symbols: 'str', callback, error_handler=None):
+ """
+ Subscribe order changing event. If a order is created, canceled etc, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(order_update_event: 'OrderUpdateEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list" : symbol_list,
+ }
+
+ from huobi.service.trade.sub_order_update_v2 import SubOrderUpdateV2Service
+ SubOrderUpdateV2Service(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def req_order_list(self, symbol: 'str', account_id: int, callback, order_states:'str',
+ order_types:'str'=None, start_date:'str'=None, end_date:'str'=None, from_id=None,
+ direct=None, size=None, client_req_id:'str'=None, error_handler=None):
+ """
+ request order list.
+
+ :param symbol: The symbol, like "btcusdt".
+ :param order_states: order status, can be one state or many state sepearted by comma, such as "submitted,partial-filled,partial-canceled,filled,canceled,created"
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(candlestick_event: 'CandlestickEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+ check_should_not_none(symbol, "symbol")
+ check_should_not_none(order_states, "states")
+ check_should_not_none(account_id, "account-d")
+ check_should_not_none(callback, "callback")
+ params = {
+ "symbol": symbol,
+ "account-id" : account_id,
+ "states" : order_states,
+ "types" : order_types,
+ "start-date" : start_date,
+ "end-date" : end_date,
+ "from": from_id,
+ "direct" : direct,
+ "size" : size,
+ "client-req-id" : client_req_id
+ }
+
+ from huobi.service.trade.req_order_list import ReqOrderListService
+ ReqOrderListService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def req_order_detail(self, order_id: 'str', callback,
+ client_req_id:'str'=None, error_handler=None):
+ """
+ Subscribe candlestick/kline event. If the candlestick/kline is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param interval: The candlestick/kline interval, MIN1, MIN5, DAY1 etc.
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(candlestick_event: 'CandlestickEvent'):
+ pass
+ :param client_req_id: client request ID
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+ check_should_not_none(order_id, "order_id")
+ check_should_not_none(callback, "callback")
+ params = {
+ "order-id": order_id,
+ "cid": client_req_id,
+ }
+
+ from huobi.service.trade.req_order_detail import ReqOrderDetailService
+ ReqOrderDetailService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def get_order(self, order_id: 'int') -> Order:
+ """
+ Get the details of an order.
+
+ :param order_id: The order id. (mandatory)
+ :return: The information of order.
+ """
+ check_should_not_none(order_id, "order_id")
+
+ params = {
+ "order_id": order_id,
+ }
+
+ from huobi.service.trade.get_order_by_id import GetOrderByIdService
+ return GetOrderByIdService(params).request(**self.__kwargs)
+
+ def get_order_by_client_order_id(self, client_order_id):
+ check_should_not_none(client_order_id, "clientOrderId")
+
+ params = {
+ "clientOrderId": client_order_id,
+ }
+
+ from huobi.service.trade.get_order_by_client_order_id import GetOrderByClientOrderIdService
+ return GetOrderByClientOrderIdService(params).request(**self.__kwargs)
+
+ def get_orders(self, symbol: 'str', order_state: 'OrderState', order_type: 'OrderType' = None,
+ start_date: 'str' = None, end_date: 'str' = None, start_id: 'int' = None,
+ size: 'int' = None, direct=None) -> list:
+ check_symbol(symbol)
+ check_should_not_none(order_state, "order_state")
+ start_date = format_date(start_date, "start_date")
+ end_date = format_date(end_date, "end_date")
+
+ params = {
+ "symbol" : symbol,
+ "types" : order_type,
+ "start-date" : start_date,
+ "end-date" : end_date,
+ "from" : start_id,
+ "states" : order_state,
+ "size" : size,
+ "direct" : direct
+ }
+
+ from huobi.service.trade.get_orders import GetOrdersService
+ return GetOrdersService(params).request(**self.__kwargs)
+
+ def get_open_orders(self, symbol: 'str', account_id: 'int', side: 'OrderSide' = None,
+ size: 'int' = None, from_id=None, direct=None) -> list:
+ """
+ The request of get open orders.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param account_id: account id (mandatory)
+ :param side: The order side, buy or sell. If no side defined, will return all open orders of the account. (optional)
+ :param size: The number of orders to return. Range is [1, 500]. (optional)
+ :param direct: 1:prev order by ID asc from from_id, 2:next order by ID desc from from_id
+ :param from_id: start ID for search
+ :return: The orders information.
+ """
+ check_symbol(symbol)
+ check_range(size, 1, 500, "size")
+ check_should_not_none(account_id, "account_id")
+ params = {
+ "symbol" : symbol,
+ "account-id" : account_id,
+ "side" : side,
+ "size" : size,
+ "from" : from_id,
+ "direct" : direct
+ }
+
+ from huobi.service.trade.get_open_orders import GetOpenOrdersService
+ return GetOpenOrdersService(params).request(**self.__kwargs)
+
+ def get_history_orders(self, symbol=None, start_time=None, end_time=None, size=None, direct=None)-> list:
+ """
+ Transfer Asset between Futures and Contract.
+
+ :param direct:
+ :param symbol: The target sub account uid to transfer to or from. (optional)
+ :param start_time: The crypto currency to transfer. (optional)
+ :param end_time: The amount of asset to transfer. (optional)
+ :param size: The type of transfer, need be "futures-to-pro" or "pro-to-futures" (optional)
+ :return: The Order list.
+ """
+ params = {
+ "symbol" :symbol,
+ "start-time" : start_time,
+ "end-time" : end_time,
+ "size" : size,
+ "direct" : direct
+ }
+
+ from huobi.service.trade.get_history_orders import GetHistoryOrdersService
+ return GetHistoryOrdersService(params).request(**self.__kwargs)
+
+ def get_match_result(self, symbol: 'str', order_type: 'OrderSide' = None, start_date: 'str' = None,
+ end_date: 'str' = None,
+ size: 'int' = None,
+ from_id: 'int' = None,
+ direct:'str'=None):
+ """
+ Search for the trade records of an account.
+
+ :param symbol: The symbol, like "btcusdt" (mandatory).
+ :param order_type: The types of order to include in the search (optional).
+ :param start_date: Search starts date in format yyyy-mm-dd. (optional).
+ :param end_date: Search ends date in format yyyy-mm-dd. (optional).
+ :param size: The number of orders to return, range [1-100]. (optional).
+ :param from_id: Search order id to begin with. (optional).
+ :return:
+ """
+
+ check_symbol(symbol)
+ start_date = format_date(start_date, "start_date")
+ end_date = format_date(end_date, "end_date")
+ check_range(size, 1, 100, "size")
+
+ params = {
+ "symbol" : symbol,
+ "start-date" : start_date,
+ "end-date" : end_date,
+ "types" : order_type,
+ "size" : size,
+ "from" : from_id,
+ "direct" : direct
+ }
+
+ from huobi.service.trade.get_match_results import GetMatchResultsService
+ return GetMatchResultsService(params).request(**self.__kwargs)
+
+ def get_match_results_by_order_id(self, order_id: 'int') -> list:
+ """
+ Get detail match results of an order.
+
+ :param order_id: The order id. (mandatory)
+ :return: The list of match result.
+ """
+ check_should_not_none(order_id, "order_id")
+
+ params = {
+ "order_id": order_id
+ }
+
+ from huobi.service.trade.get_match_results_by_order_id import GetMatchResultsByOrderIdService
+ return GetMatchResultsByOrderIdService(params).request(**self.__kwargs)
+
+ def order_source_desc(self, account_type):
+ default_source = "api"
+ if account_type:
+ if account_type == AccountType.MARGIN:
+ return "margin-api"
+ return default_source
+
+ def create_order_param_check(self, symbol: 'str', account_id: 'int', order_type: 'OrderType', amount: 'float',
+ price: 'float', source:'str', client_order_id=None, stop_price=None, operator=None):
+ check_symbol(symbol)
+ check_should_not_none(account_id, "account_id")
+ check_should_not_none(order_type, "order_type")
+ check_should_not_none(amount, "amount")
+ check_should_not_none(source, "source")
+
+ if order_type == OrderType.SELL_LIMIT \
+ or order_type == OrderType.BUY_LIMIT \
+ or order_type == OrderType.BUY_LIMIT_MAKER \
+ or order_type == OrderType.SELL_LIMIT_MAKER:
+ check_should_not_none(price, "price")
+ if order_type in [OrderType.SELL_MARKET, OrderType.BUY_MARKET]:
+ price = None
+
+ params = {
+ "account-id" : account_id,
+ "amount" : amount,
+ "price": price,
+ "symbol": symbol,
+ "type": order_type,
+ "source": source,
+ "client-order-id": client_order_id,
+ "stop-price": stop_price,
+ "operator": operator
+ }
+
+ return params
+
+ def create_order(self, symbol: 'str', account_id: 'int', order_type: 'OrderType', amount: 'float',
+ price: 'float', source:'str', client_order_id=None, stop_price=None, operator=None) -> int:
+ """
+ Make an order in huobi.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param account_id: Account id. (mandatory)
+ :param order_type: The order type. (mandatory)
+ :param source: The order source. (mandatory)
+ for spot, it's "api", see OrderSource.API
+ for margin, it's "margin-api", see OrderSource.MARGIN_API
+ for super margin, it's "super-margin-api", see OrderSource.SUPER_MARGIN_API
+ :param amount: The amount to buy (quote currency) or to sell (base currency). (mandatory)
+ :param price: The limit price of limit order, only needed for limit order. (mandatory for buy-limit, sell-limit, buy-limit-maker and sell-limit-maker)
+ :param client_order_id: unique Id which is user defined and must be unique in recent 24 hours
+ :param stop_price: Price for auto sell to get the max benefit
+ :param operator: the condition for stop_price, value can be "gte" or "lte", gte – greater than and equal (>=), lte – less than and equal (<=)
+ :return: The order id.
+ """
+
+ params = self.create_order_param_check(symbol, account_id, order_type, amount,
+ price, source, client_order_id, stop_price, operator)
+ from huobi.service.trade.post_create_order import PostCreateOrderService
+ return PostCreateOrderService(params).request(**self.__kwargs)
+
+ def create_spot_order(self, symbol: 'str', account_id: 'int', order_type: 'OrderType', amount: 'float',
+ price: 'float', client_order_id=None, stop_price=None,
+ operator=None) -> int:
+ order_source = OrderSource.API
+ return self.create_order(symbol=symbol, account_id=account_id, order_type=order_type, amount=amount,
+ price=price, source=order_source, client_order_id=client_order_id, stop_price=stop_price,
+ operator=operator)
+
+ def create_margin_order(self, symbol: 'str', account_id: 'int', order_type: 'OrderType', amount: 'float',
+ price: 'float', client_order_id=None, stop_price=None,
+ operator=None) -> int:
+ order_source = OrderSource.MARGIN_API
+ return self.create_order(symbol=symbol, account_id=account_id, order_type=order_type, amount=amount,
+ price=price, source=order_source, client_order_id=client_order_id,
+ stop_price=stop_price,
+ operator=operator)
+
+ def create_super_margin_order(self, symbol: 'str', account_id: 'int', order_type: 'OrderType', amount: 'float',
+ price: 'float', client_order_id=None, stop_price=None,
+ operator=None) -> int:
+ order_source = OrderSource.SUPER_MARGIN_API
+ return self.create_order(symbol=symbol, account_id=account_id, order_type=order_type, amount=amount,
+ price=price, source=order_source, client_order_id=client_order_id,
+ stop_price=stop_price,
+ operator=operator)
+
+ def cancel_order(self, symbol, order_id):
+ check_symbol(symbol)
+ check_should_not_none(order_id, "order_id")
+
+ params = {
+ "order_id" : order_id
+ }
+
+ from huobi.service.trade.post_cancel_order import PostCancelOrderService
+ return PostCancelOrderService(params).request(**self.__kwargs)
+
+ def cancel_orders(self, symbol, order_id_list)->BatchCancelResult:
+ """
+ Submit cancel request for cancelling multiple orders.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param order_id_list: The list of order id. the max size is 50. (mandatory)
+ :return: No return
+ """
+ check_symbol(symbol)
+ check_should_not_none(order_id_list, "order_id_list")
+ check_list(order_id_list, 1, 50, "order_id_list")
+
+ string_list = list()
+ for order_id in order_id_list:
+ string_list.append(str(order_id))
+
+ params = {
+ "order-ids" : string_list
+ }
+
+ from huobi.service.trade.post_batch_cancel_order import PostBatchCancelOrderService
+ return PostBatchCancelOrderService(params).request(**self.__kwargs)
+
+ def cancel_open_orders(self, account_id, symbols: 'str'=None , side=None, size=None)->BatchCancelCount:
+ """
+ Request to cancel open orders.
+
+ :param symbols: The symbol, like "btcusdt".
+ :param account_type: Account type. (mandatory)
+ :param side: The order side, buy or sell. If no side defined, will cancel all open orders of the account. (optional)
+ :param size: The number of orders to cancel. Range is [1, 100]. (optional)
+ :return: Status of batch cancel result.
+ """
+ check_should_not_none(account_id, "account_id")
+
+ params = {
+ "account-id": account_id,
+ "symbol" : symbols,
+ "side" : side,
+ "size" : size
+ }
+
+ from huobi.service.trade.post_batch_cancel_open_order import PostBatchCancelOpenOrderService
+ return PostBatchCancelOpenOrderService(params).request(**self.__kwargs)
+
+ def cancel_client_order(self, client_order_id)->int:
+ """
+ Request to cancel open orders.
+
+ :param client_order_id: user defined unique order id
+ """
+ check_should_not_none(client_order_id, "client-order-id")
+
+ params = {
+ "client-order-id" : client_order_id
+ }
+
+ from huobi.service.trade.post_cancel_client_order import PostCancelClientOrderService
+ return PostCancelClientOrderService(params).request(**self.__kwargs)
+
+ def transfer_between_futures_and_pro(self, currency: 'str', amount: 'float',
+ transfer_type: 'TransferFuturesPro')-> int:
+ """
+ Transfer Asset between Futures and Contract.
+
+ :param sub_uid: The target sub account uid to transfer to or from. (mandatory)
+ :param currency: The crypto currency to transfer. (mandatory)
+ :param amount: The amount of asset to transfer. (mandatory)
+ :param transfer_type: The type of transfer, need be "futures-to-pro" or "pro-to-futures" (mandatory)
+ :return: The order id.
+ """
+ check_currency(currency)
+ check_should_not_none(currency, "currency")
+ check_should_not_none(amount, "amount")
+ check_should_not_none(transfer_type, "transfer_type")
+ params = {
+ "currency" : currency,
+ "amount" : amount,
+ "type" : transfer_type
+
+ }
+
+ from huobi.service.trade.post_transfer_futures_pro import PostTransferFuturesProService
+ return PostTransferFuturesProService(params).request(**self.__kwargs)
+
+ def batch_create_order(self, order_config_list) -> int:
+ """
+ Make an order in huobi.
+ :param order_config_list: order config list, it can batch create orders, and each order config check as below
+ : items as below
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param account_type: Account type. (mandatory)
+ :param order_type: The order type. (mandatory)
+ :param amount: The amount to buy (quote currency) or to sell (base currency). (mandatory)
+ :param price: The limit price of limit order, only needed for limit order. (mandatory for buy-limit, sell-limit, buy-limit-maker and sell-limit-maker)
+ :param client_order_id: unique Id which is user defined and must be unique in recent 24 hours
+ :param stop_price: Price for auto sell to get the max benefit
+ :param operator: the condition for stop_price, value can be "gte" or "lte", gte – greater than and equal (>=), lte – less than and equal (<=)
+ :return: The order id.
+ """
+
+ check_should_not_none(order_config_list, "order_config_list")
+ check_list(order_config_list, 1, 10, "create order config list")
+
+ new_config_list = list()
+ for item in order_config_list:
+ new_item = self.create_order_param_check(
+ item.get("symbol", None),
+ item.get("account_id", None),
+ item.get("order_type", None),
+ item.get("amount", None),
+ item.get("price", None),
+ item.get("source", None),
+ item.get("client_order_id", None),
+ item.get("stop-price", None),
+ item.get("operator", None))
+
+ new_config_list.append(new_item)
+
+ from huobi.service.trade.post_batch_create_order import PostBatchCreateOrderService
+ return PostBatchCreateOrderService(new_config_list).request(**self.__kwargs)
+
+ def sub_trade_clearing(self, symbols: 'str', callback, error_handler=None):
+ """
+ Subscribe trade clearing by symbol
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ "*" for all symbols
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(price_depth_event: 'PriceDepthEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+
+ :return: No return
+ """
+ check_should_not_none(symbols, "symbols")
+ symbol_list = symbols.split(",")
+ if ("*" in symbol_list):
+ symbol_list = ["*"]
+ else:
+ check_symbol_list(symbol_list)
+
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ }
+
+ from huobi.service.trade.sub_trade_clearing_v2 import SubTradeClearingV2Service
+ SubTradeClearingV2Service(params).subscribe(callback, error_handler, **self.__kwargs)
diff --git a/huobi/client/margin.py b/huobi/client/margin.py
new file mode 100644
index 0000000..0fe3596
--- /dev/null
+++ b/huobi/client/margin.py
@@ -0,0 +1,363 @@
+from huobi.utils.input_checker import *
+
+
+class MarginClient(object):
+
+ def __init__(self, **kwargs):
+ """
+ Create the request client instance.
+ :param kwargs: The option of request connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: The URL name like "https://api.huobi.pro".
+ init_log: to init logger
+ """
+ self.__kwargs = kwargs
+
+ def post_transfer_in_margin(self, symbol: 'str', currency: 'str', amount: 'float') -> int:
+ """
+ Transfer asset from spot account to margin account.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param currency: The currency of transfer. (mandatory)
+ :param amount: The amount of transfer. (mandatory)
+ :return:
+ """
+ check_symbol(symbol)
+ check_should_not_none(currency, "currency")
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "symbol": symbol,
+ "currency": currency,
+ "amount": amount
+ }
+
+ from huobi.service.margin.post_transfer_in_margin import PostTransferInMarginService
+ return PostTransferInMarginService(params).request(**self.__kwargs)
+
+ def post_transfer_out_margin(self, symbol: 'str', currency: 'str', amount: 'float') -> int:
+ """
+ Transfer asset from margin account to spot account.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param currency: The currency of transfer. (mandatory)
+ :param amount: The amount of transfer. (mandatory)
+ :return:
+ """
+ check_symbol(symbol)
+ check_should_not_none(currency, "currency")
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "symbol": symbol,
+ "currency": currency,
+ "amount": amount
+ }
+
+ from huobi.service.margin.post_transfer_out_margin import PostTransferOutMarginService
+ return PostTransferOutMarginService(params).request(**self.__kwargs)
+
+ def get_margin_account_balance(self, symbol: 'str') -> list:
+ """
+ Get the Balance of the Margin Loan Account.
+
+ :param symbol: The currency, like "btc". (mandatory)
+ :return: The margin loan account detail list.
+ """
+ check_symbol(symbol)
+
+ params = {
+ "symbol": symbol
+ }
+
+ from huobi.service.margin.get_margin_account_balance import GetMarginAccountBalanceService
+ return GetMarginAccountBalanceService(params).request(**self.__kwargs)
+
+ def post_create_margin_order(self, symbol: 'str', currency: 'str', amount: 'float') -> int:
+ """
+ Submit a request to borrow with margin account.
+
+ :param symbol: The trading symbol to borrow margin, e.g. "btcusdt", "bccbtc". (mandatory)
+ :param currency: The currency to borrow,like "btc". (mandatory)
+ :param amount: The amount of currency to borrow. (mandatory)
+ :return: The margin order id.
+ """
+ check_symbol(symbol)
+ check_should_not_none(currency, "currency")
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "symbol": symbol,
+ "currency": currency,
+ "amount": amount
+ }
+
+ from huobi.service.margin.post_create_margin_order import PostCreateMarginOrderService
+ return PostCreateMarginOrderService(params).request(**self.__kwargs)
+
+ def post_repay_margin_order(self, loan_id: 'int', amount: 'float') -> int:
+ """
+ Get the margin loan records.
+
+ :param load_id: The previously returned order id when loan order was created. (mandatory)
+ :param amount: The amount of currency to repay. (mandatory)
+ :return: The margin order id.
+ """
+ check_should_not_none(loan_id, "loan_id")
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "loan_id": loan_id,
+ "amount": amount
+ }
+
+ from huobi.service.margin.post_repay_margin_order import PostRepayMarginOrderService
+ return PostRepayMarginOrderService(params).request(**self.__kwargs)
+
+ def get_margin_loan_orders(self, symbol: 'str', start_date: 'str' = None, end_date: 'str' = None,
+ states: 'LoanOrderState' = None, from_id: 'int' = None,
+ size: 'int' = None, direction: 'QueryDirection' = None) -> list:
+ """
+ Get the margin loan records.
+
+ :param symbol: The symbol, like "btcusdt" (mandatory).
+ :param start_date: The search starts date in format yyyy-mm-dd. (optional).
+ :param end_date: The search end date in format yyyy-mm-dd.(optional, can be null).
+ :param states: The loan order states, it could be created, accrual, cleared or invalid. (optional)
+ :param from_id: Search order id to begin with. (optional)
+ :param size: The number of orders to return.. (optional)
+ :param direction: The query direction, prev or next. (optional)
+ :return: The list of the margin loan records.
+ """
+
+ check_symbol(symbol)
+ start_date = format_date(start_date, "start_date")
+ end_date = format_date(end_date, "end_date")
+
+ params = {
+ "symbol": symbol,
+ "start-date": start_date,
+ "end-date": end_date,
+ "states": states,
+ "from": from_id,
+ "size": size,
+ "direct": direction
+ }
+
+ from huobi.service.margin.get_margin_loan_orders import GetMarginLoanOrdersService
+ return GetMarginLoanOrdersService(params).request(**self.__kwargs)
+
+ def get_margin_loan_info(self, symbols: 'str' = None) -> list:
+ """
+ The request of get margin loan info, can return currency loan info list.
+
+ :param symbols: The symbol, like "btcusdt,htusdt". (optional)
+ :return: The cross margin loan info.
+ """
+
+ check_symbol(symbols)
+ params = {
+ "symbols": symbols
+ }
+
+ from huobi.service.margin.get_margin_loan_info import GetMarginLoanInfoService
+ return GetMarginLoanInfoService(params).request(**self.__kwargs)
+
+ def get_cross_margin_loan_info(self) -> list:
+ """
+ The request of currency loan info list.
+
+ :return: The cross margin loan info list.
+ """
+ params = {}
+
+ from huobi.service.margin.get_cross_margin_loan_info import GetCrossMarginLoanInfoService
+ return GetCrossMarginLoanInfoService(params).request(**self.__kwargs)
+
+ def post_cross_margin_transfer_in(self, currency: 'str', amount: 'float') -> int:
+ """
+ transfer currency to cross account.
+
+ :param currency: currency name (mandatory)
+ :param amount: transfer amount (mandatory)
+ :return: return transfer id.
+ """
+ check_should_not_none(currency, "currency")
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "amount": amount,
+ "currency": currency
+ }
+
+ from huobi.service.margin.post_cross_margin_transfer_in import PostCrossMarginTransferInService
+ return PostCrossMarginTransferInService(params).request(**self.__kwargs)
+
+ def post_cross_margin_transfer_out(self, currency: 'str', amount: 'float') -> int:
+ """
+ transfer currency to cross account.
+
+ :param currency: currency name (mandatory)
+ :param amount: transfer amount (mandatory)
+ :return: return transfer id.
+ """
+ check_should_not_none(currency, "currency")
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "amount": amount,
+ "currency": currency
+ }
+
+ from huobi.service.margin.post_cross_margin_transfer_out import PostCrossMarginTransferOutService
+ return PostCrossMarginTransferOutService(params).request(**self.__kwargs)
+
+ def post_cross_margin_create_loan_orders(self, currency: 'str', amount: 'float') -> int:
+ """
+ create cross margin loan orders
+
+ :param currency: currency name (mandatory)
+ :param amount: transfer amount (mandatory)
+ :return: return order id.
+ """
+
+ check_should_not_none(currency, "currency")
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "amount": amount,
+ "currency": currency
+ }
+
+ from huobi.service.margin.post_cross_margin_create_loan_orders import PostCrossMarginCreateLoanOrdersService
+ return PostCrossMarginCreateLoanOrdersService(params).request(**self.__kwargs)
+
+ def post_cross_margin_loan_order_repay(self, order_id: 'str', amount: 'float'):
+ """
+ repay cross margin loan orders
+
+ :param order_id: order_id for loan (mandatory)
+ :param amount: transfer amount (mandatory)
+ :return: return order id.
+ """
+
+ check_should_not_none(order_id, "order-id")
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "amount": amount,
+ "order-id": order_id
+ }
+
+ from huobi.service.margin.post_cross_margin_loan_order_repay import PostCrossMarginLoanOrderRepayService
+ return PostCrossMarginLoanOrderRepayService(params).request(**self.__kwargs)
+
+ def get_cross_margin_loan_orders(self, currency: 'str' = None, state: 'str' = None,
+ start_date: 'str' = None, end_date: 'str' = None,
+ from_id: 'int' = None, size: 'int' = None, direct: 'str' = None,
+ sub_uid: 'int' = None) -> list:
+ """
+ get cross margin loan orders
+
+ :return: return list.
+ """
+ params = {
+ "currency": currency,
+ "state": state,
+ "start-date": start_date,
+ "end-date": end_date,
+ "from": from_id,
+ "size": size,
+ "direct": direct,
+ "sub-uid": sub_uid
+ }
+
+ from huobi.service.margin.get_cross_margin_loan_orders import GetCrossMarginLoanOrdersService
+ return GetCrossMarginLoanOrdersService(params).request(**self.__kwargs)
+
+ def get_cross_margin_account_balance(self, sub_uid: 'int' = None):
+ """
+ get cross margin account balance
+
+ :return: cross-margin account.
+ """
+ params = {
+ "sub-uid": sub_uid
+ }
+
+ from huobi.service.margin.get_cross_margin_account_balance import GetCrossMarginAccountBalanceService
+ return GetCrossMarginAccountBalanceService(params).request(**self.__kwargs)
+
+ def post_general_repay_loan(self, account_id: 'str', currency: 'str', amount: 'float',
+ transact_id: 'str' = None) -> list:
+ """
+ Repay Margin Loan(Cross).
+
+ :param account_id: repayment account ID .(mandatory)
+ :param currency: repayment currency. (mandatory).
+ :param amount: repayment amount.(mandatory).
+ :param transact_id: loan transaction ID. (optional)
+ """
+ check_should_not_none(account_id, "account_id")
+ check_should_not_none(currency, "currency")
+ check_should_not_none(amount, "amount")
+
+ params = {
+ "accountId": account_id,
+ "currency": currency,
+ "amount": amount,
+ "transact_id": transact_id
+ }
+
+ from huobi.service.margin.post_general_repay_loan import PostGeneralRepayLoanService
+ return PostGeneralRepayLoanService(params).request(**self.__kwargs)
+
+ def get_general_repayment_loan_records(self, repay_id: 'str' = None, account_id: 'str' = None,
+ currency: 'str' = None, start_time: 'int' = None, end_time: 'int' = None,
+ sort: 'str' = None, limit: 'int' = None, from_id: 'int' = None) -> list:
+
+ """
+ Get Repayment Record Reference(Cross).
+
+ :param repay_id: repayment transaction ID. (optional)
+ :param account_id: account ID (default value: all accounts) (optional).
+ :param currency: borrowing/lending currency (default value: all currencies). (optional)
+ :param start_time: start time (unix time in millisecond; range: [(endTime – x D), endTime]; default value: (endTime – x D) (optional)
+ :param end_time: end time (unix time in millisecond;range: [(present time – y D), present time]; default value: present time) (optional)
+ :param sort: sort direction (virtual value: asc, desc; default value: desc) (optional)
+ :param limit: max return items per page (range: [1,100]; default value: 50) (optional)
+ :param from_id: search original ID (only available when searching for the next page) (optional)
+ """
+
+ params = {
+
+ }
+ if repay_id is not None:
+ params['repayId'] = repay_id
+
+ if account_id is not None:
+ params['accountId'] = account_id
+
+ if account_id is not None:
+ params['currency'] = currency
+
+ if start_time is not None:
+ params['startTime'] = start_time
+
+ if end_time is not None:
+ params['endTime'] = end_time
+
+ if sort is not None:
+ params['sort'] = sort
+
+ if limit is not None:
+ params['limit'] = limit
+
+ if from_id is not None:
+ params['fromId'] = from_id
+
+ from huobi.service.margin.get_general_repayment_loan_records import GetGeneralRepaymentLoanRecordsService
+ return GetGeneralRepaymentLoanRecordsService(params).request(**self.__kwargs)
+
+ return
diff --git a/huobi/client/market.py b/huobi/client/market.py
new file mode 100644
index 0000000..7d281be
--- /dev/null
+++ b/huobi/client/market.py
@@ -0,0 +1,496 @@
+from huobi.constant import *
+from huobi.model.market import *
+from huobi.utils import *
+from huobi.utils.input_checker import check_in_list
+
+
+class MarketClient(object):
+
+ def __init__(self, **kwargs):
+ """
+ Create the request client instance.
+ :param kwargs: The option of request connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: The URL name like "https://api.huobi.pro".
+ init_log: to init logger
+ """
+ self.__kwargs = kwargs
+
+ def get_candlestick(self, symbol, period, size=200):
+ """
+ Get the candlestick/kline for the specified symbol. The data number is 150 as default.
+
+ :param symbol: The symbol, like "btcusdt". To query hb10, put "hb10" at here. (mandatory)
+ :param period: The candlestick/kline interval, MIN1, MIN5, DAY1 etc. (mandatory)
+ :param size: The start time of of requested candlestick/kline data. (optional)
+ :return: The list of candlestick/kline data.
+ """
+ check_symbol(symbol)
+ check_should_not_none(period, "period")
+ check_range(size, 1, 2000, "size")
+
+ params = {
+ "symbol": symbol,
+ "period": period,
+ "size": size
+ }
+ from huobi.service.market.get_candlestick import GetCandleStickService
+ return GetCandleStickService(params).request(**self.__kwargs)
+
+ def sub_candlestick(self, symbols: 'str', interval: 'CandlestickInterval', callback, error_handler):
+
+ """
+ Subscribe candlestick/kline event. If the candlestick/kline is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param interval: The candlestick/kline interval, MIN1, MIN5, DAY1 etc.
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(candlestick_event: 'CandlestickEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(interval, "interval")
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ "interval": interval,
+ }
+
+ from huobi.service.market.sub_candlestick import SubCandleStickService
+ SubCandleStickService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def req_candlestick(self, symbols: 'str', interval: 'CandlestickInterval', callback,
+ from_ts_second=None, end_ts_second=None, error_handler=None):
+ """
+ Subscribe candlestick/kline event. If the candlestick/kline is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param interval: The candlestick/kline interval, MIN1, MIN5, DAY1 etc.
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(candlestick_event: 'CandlestickEvent'):
+ pass
+ :param from_ts_second : data from timestamp [it's second]
+ :param end_ts_second : data util timestamp [it's second]
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(interval, "interval")
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ "interval": interval,
+ "from_ts_second": from_ts_second,
+ "end_ts_second": end_ts_second
+ }
+
+ from huobi.service.market.req_candlestick import ReqCandleStickService
+ ReqCandleStickService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def get_pricedepth(self, symbol: 'str', depth_type: 'str', depth_size: 'int' = None) -> PriceDepth:
+ """
+ Get the Market Depth of a symbol.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param depth_type: The tpye, like "step0" to "step5". (mandatory)
+ :param depth_size(optional): The maximum number of Market Depth step0 requested. range [1 - 150], default is 150
+ The maximum number of Market Depth step1,step2,step3,step4,step5 requested. size is in [5, 10, 20], default is 20.
+ :return: Market Depth data.
+ """
+
+ check_symbol(symbol)
+ check_in_list(depth_type, [DepthStep.STEP0, DepthStep.STEP1, DepthStep.STEP2, DepthStep.STEP3, DepthStep.STEP4,
+ DepthStep.STEP5], "depth_type")
+ params = {
+ "symbol": symbol,
+ "type": depth_type,
+ # "depth": depth_size
+ }
+
+ from huobi.service.market.get_pricedepth import GetPriceDepthService
+ ret_data = GetPriceDepthService(params).request(**self.__kwargs)
+
+ if depth_size is not None:
+ if (ret_data.bids is not None) and (len(ret_data.bids) > depth_size):
+ ret_data.bids = ret_data.bids[0:depth_size]
+
+ if (ret_data.asks is not None) and (len(ret_data.asks) > depth_size):
+ ret_data.asks = ret_data.asks[0:depth_size]
+
+ return ret_data
+
+ @staticmethod
+ def get_depth_step_list():
+ return [DepthStep.STEP0,
+ DepthStep.STEP1,
+ DepthStep.STEP2,
+ DepthStep.STEP3,
+ DepthStep.STEP4,
+ DepthStep.STEP5]
+
+ @staticmethod
+ def get_valid_depth_step(value, defalut_value):
+ step_list = MarketClient.get_depth_step_list()
+ if value in step_list:
+ return value
+ else:
+ return defalut_value
+
+ def sub_pricedepth(self, symbols: 'str', depth_step: 'str', callback, error_handler=None):
+ """
+ Subscribe price depth event. If the price depth is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param depth_step: The depth precision, string from step0 to step5.
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(price_depth_event: 'PriceDepthEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+
+ :return: No return
+ """
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ new_step = MarketClient.get_valid_depth_step(value=depth_step, defalut_value=DepthStep.STEP0)
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ "step": new_step,
+ }
+
+ from huobi.service.market.sub_pricedepth import SubPriceDepthService
+ SubPriceDepthService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def sub_pricedepth_bbo(self, symbols: 'str', callback, error_handler=None):
+ """
+ Subscribe price depth event. If the price depth is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(price_depth_event: 'PriceDepthEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+
+ :return: No return
+ """
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ }
+
+ from huobi.service.market.sub_pricedepth_bbo import SubPriceDepthBboService
+ SubPriceDepthBboService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def req_pricedepth(self, symbols: 'str', depth_step: 'str', callback, error_handler=None):
+ """
+ Subscribe price depth event. If the price depth is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param depth_step: The depth precision, string from step0 to step5.
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(price_depth_event: 'PriceDepthEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+
+ :return: No return
+ """
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ new_step = MarketClient.get_valid_depth_step(value=depth_step, defalut_value=DepthStep.STEP0)
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ "step": new_step,
+ }
+
+ from huobi.service.market.req_pricedepth import ReqPriceDepthService
+ ReqPriceDepthService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def get_market_detail(self, symbol: 'str') -> MarketDetail:
+ """
+ Get trade statistics in 24 hours.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :return: Trade statistics.
+ """
+
+ check_symbol(symbol)
+
+ params = {
+ "symbol": symbol,
+ }
+
+ from huobi.service.market.get_market_detail import GetMarketDetailService
+ return GetMarketDetailService(params).request(**self.__kwargs)
+
+ def sub_market_detail(self, symbols: 'str', callback, error_handler=None):
+ """
+ Subscribe 24 hours trade statistics event. If statistics is generated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(trade_statistics_event: 'TradeStatisticsEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ }
+
+ from huobi.service.market.sub_market_detail import SubMarketDetailService
+ SubMarketDetailService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def req_market_detail(self, symbols: 'str', callback, error_handler=None):
+ """
+ Subscribe 24 hours trade statistics event. If statistics is generated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(trade_statistics_event: 'TradeStatisticsEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ }
+
+ from huobi.service.market.req_market_detail import ReqMarketDetailService
+ ReqMarketDetailService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def get_market_trade(self, symbol: 'str') -> list:
+ """
+ Get the most recent trades with their price, volume and direction.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :return: The list of trade.
+ """
+
+ check_symbol(symbol)
+
+ params = {
+ "symbol": symbol,
+ }
+
+ from huobi.service.market.get_market_trade import GetMarketTradeService
+ return GetMarketTradeService(params).request(**self.__kwargs)
+
+ def get_history_trade(self, symbol: 'str', size: 'int' = None) -> list:
+ """
+ Get the most recent trades with their price, volume and direction.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param size: The number of historical trade requested, range [1 - 2000] (optional)
+ :return: The list of trade.
+ """
+
+ check_symbol(symbol)
+ check_range(size, 1, 2000, "size")
+
+ params = {
+ "symbol": symbol,
+ "size": size
+ }
+
+ from huobi.service.market.get_history_trade import GetHistoryTradeService
+ return GetHistoryTradeService(params).request(**self.__kwargs)
+
+ def sub_trade_detail(self, symbols: 'str', callback, error_handler=None):
+ """
+ Subscribe price depth event. If the price depth is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(trade_event: 'TradeEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ }
+
+ from huobi.service.market.sub_trade_detail import SubTradeDetailService
+ SubTradeDetailService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def req_trade_detail(self, symbols: 'str', callback, error_handler=None):
+ """
+ Subscribe price depth event. If the price depth is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(trade_event: 'TradeEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ }
+
+ from huobi.service.market.req_trade_detail import ReqTradeDetailService
+ ReqTradeDetailService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def get_market_detail_merged(self, symbol):
+ check_symbol(symbol)
+ params = {
+ "symbol": symbol
+ }
+
+ from huobi.service.market.get_market_detail_merged import GetMarketDetailMergedService
+ return GetMarketDetailMergedService(params).request(**self.__kwargs)
+
+ def get_market_tickers(self) -> list:
+ """
+ get market tickers
+
+ :return: market ticker list.
+ """
+
+ params = {}
+ from huobi.service.market.get_market_tickers import GetMarketTickersService
+ return GetMarketTickersService(params).request(**self.__kwargs)
+
+ """
+ increase mbp(market by price)
+ """
+
+ def sub_mbp_increase(self, symbols: 'str', levels: 'int', callback, error_handler=None):
+ """
+ Subscribe mbp event. If the mbp is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param levels: level, 5,10,20,150. current only support 150
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(price_depth_event: 'PriceDepthEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+
+ :return: No return
+ """
+ check_should_not_none(symbols, "symbol")
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(levels, "levels")
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ "levels": levels
+ }
+
+ from huobi.service.market.sub_mbp_increase import SubMbpIncreaseService
+ SubMbpIncreaseService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ """
+ subscribe full mbp(market by price)
+ """
+
+ def sub_mbp_full(self, symbols: 'str', levels: 'int', callback, error_handler=None):
+ """
+ Subscribe full mbp event. If the mbp is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param levels: level, 5,10,20
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(price_depth_event: 'PriceDepthEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+
+ :return: No return
+ """
+ check_should_not_none(symbols, "symbol")
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(levels, "levels")
+ check_in_list(levels, [MbpLevel.MBP5, MbpLevel.MBP10, MbpLevel.MBP20], "levels")
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ "levels": levels
+ }
+
+ from huobi.service.market.sub_mbp_full import SubMbpFullService
+ SubMbpFullService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def req_mbp(self, symbols: 'str', levels: 'int', callback, auto_close=True, error_handler=None):
+ """
+ Subscribe mbp event. If the mbp is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param levels: level, 5,10,20,150. current only support 150
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(price_depth_event: 'PriceDepthEvent'):
+ pass
+ :param auto_close : close websocket connection after get data
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+
+ :return: No return
+ """
+ check_should_not_none(symbols, "symbol")
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(levels, "levels")
+ check_should_not_none(callback, "callback")
+ params = {
+ "symbol_list": symbol_list,
+ "levels": levels
+ }
+ from huobi.service.market.req_mbp import ReqMbpService
+ ReqMbpService(params).subscribe(callback, error_handler, **self.__kwargs)
diff --git a/huobi/client/subuser.py b/huobi/client/subuser.py
new file mode 100644
index 0000000..bda5809
--- /dev/null
+++ b/huobi/client/subuser.py
@@ -0,0 +1,115 @@
+from huobi.utils import *
+from huobi.constant import *
+from huobi.utils.input_checker import check_in_list
+
+
+class SubuserClient(object):
+ def __init__(self, **kwargs):
+ """
+ Create the request client instance.
+ :param kwargs: The option of request connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: The URL name like "https://api.huobi.pro".
+ init_log: Init logger, default is False, True will init logger handler
+ """
+ self.__kwargs = kwargs
+
+ def post_create_subuser(self, user_list):
+ check_should_not_none(user_list, 'userList')
+
+ params = user_list
+ from huobi.service.subuser.post_create_subuser import PostSubuserCreationService
+ return PostSubuserCreationService(params).request(**self.__kwargs)
+
+ def post_set_tradable_market(self, sub_uids, account_type: 'SubuserTradePrivilegeType',
+ activation: 'SubUserTradeStatus'):
+ check_should_not_none(sub_uids, 'subUids')
+ check_should_not_none(account_type, 'accountType')
+ check_should_not_none(activation, 'activation')
+
+ check_in_list(account_type,
+ [SubuserTradePrivilegeType.MARGIN, SubuserTradePrivilegeType.SUPER_MARGIN], "accountType")
+ check_in_list(activation, [SubUserTradeStatus.ACTIVATED, SubUserTradeStatus.DEACTIVATED], "activation")
+
+ params = {
+ 'subUids': sub_uids,
+ 'accountType': account_type,
+ 'activation': activation
+ }
+ from huobi.service.subuser.post_tradable_market import PostTradableMarketService
+ return PostTradableMarketService(params).request(**self.__kwargs)
+
+ def post_set_subuser_transferability(self, sub_uids: 'str', transferrable: 'bool',
+ account_type: 'AccountType' = AccountType.SPOT):
+ check_should_not_none(sub_uids, 'subUids')
+ check_should_not_none(transferrable, 'transferrable')
+ check_in_list(account_type, [AccountType.SPOT], 'accountType')
+
+ params = {
+ "subUids": sub_uids,
+ "accountType": account_type,
+ "transferrable": transferrable
+ }
+ from huobi.service.subuser.post_set_transferability import PostSetSubuserTransferability
+ return PostSetSubuserTransferability(params).request(**self.__kwargs)
+
+ def post_subuser_apikey_generate(self, otp_token: 'str', sub_uid: 'int', note: 'str', permission: 'bool',
+ ip_addresses: 'str' = None):
+ check_should_not_none(otp_token, 'otpToken')
+ check_should_not_none(sub_uid, 'subUid')
+ check_should_not_none(note, 'note')
+ check_should_not_none(permission, 'permission')
+ # check_in_list(permission, [AccountType.SPOT], 'accountType')
+
+ params = {
+ "otpToken": otp_token,
+ "subUid": sub_uid,
+ "note": note,
+ "permission": permission,
+ "ipAddresses": ip_addresses
+ }
+ from huobi.service.subuser.post_subuser_apikey_generation import PostSubuserApikeyGenerationService
+ return PostSubuserApikeyGenerationService(params).request(**self.__kwargs)
+
+ def get_user_apikey_info(self, uid: 'str', access_key: 'str' = None):
+ check_should_not_none(uid, 'uid')
+
+ params = {
+ "uid": uid,
+ "accessKey": access_key
+ }
+ from huobi.service.subuser.get_user_apikey_info import GetUserApikeyInfoService
+ return GetUserApikeyInfoService(params).request(**self.__kwargs)
+
+ def post_subuser_apikey_modification(self, sub_uid: 'str', access_key: 'str', note: 'str' = None,
+ permission: 'str' = None, ip_addresses: 'str' = None):
+ check_should_not_none(sub_uid, 'subUid')
+ check_should_not_none(access_key, 'accessKey')
+
+ params = {
+ "subUid": sub_uid,
+ "accessKey": access_key,
+ "note": note,
+ "permission": permission,
+ "ipAddresses": ip_addresses
+ }
+ from huobi.service.subuser.post_subuser_apikey_modification import PostSubuserApikeyModificationService
+ return PostSubuserApikeyModificationService(params).request(**self.__kwargs)
+
+ def post_subuser_apikey_deletion(self, sub_uid: 'str', access_key: 'str'):
+ check_should_not_none(sub_uid, 'subUid')
+ check_should_not_none(access_key, 'accessKey')
+
+ params = {
+ "subUid": sub_uid,
+ "accessKey": access_key
+ }
+ from huobi.service.subuser.post_subuser_apikey_deletion import PostSubuserApikeyDeletionService
+ return PostSubuserApikeyDeletionService(params).request(**self.__kwargs)
+
+ def get_uid(self):
+ params = {
+ }
+ from huobi.service.subuser.get_uid import GetUidService
+ return GetUidService(params).request(**self.__kwargs)
diff --git a/huobi/client/trade.py b/huobi/client/trade.py
new file mode 100644
index 0000000..5e586c1
--- /dev/null
+++ b/huobi/client/trade.py
@@ -0,0 +1,540 @@
+from huobi.constant import *
+from huobi.model.trade import *
+from huobi.utils.input_checker import *
+
+
+class TradeClient(object):
+
+ def __init__(self, **kwargs):
+ """
+ Create the request client instance.
+ :param kwargs: The option of request connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: The URL name like "https://api.huobi.pro".
+ init_log: to init logger
+ """
+ self.__kwargs = kwargs
+
+ def get_feerate(self, symbols: 'str') -> list:
+ """
+ Get the candlestick/kline for the specified symbol. The data number is 150 as default.
+
+ :param symbol: The symbol, like "btcusdt". To query hb10, put "hb10" at here. (mandatory)
+ :param interval: The candlestick/kline interval, MIN1, MIN5, DAY1 etc. (mandatory)
+ :param size: The start time of of requested candlestick/kline data. (optional)
+ :param start_time: The start time of of requested candlestick/kline data. (optional)
+ :param end_time: The end time of of requested candlestick/kline data. (optional)
+ :return: The list of candlestick/kline data.
+ """
+ check_symbol(symbols)
+
+ params = {
+ "symbols": symbols
+ }
+
+ from huobi.service.trade.get_feerate import GetFeeRateService
+ return GetFeeRateService(params).request(**self.__kwargs)
+
+ def get_transact_feerate(self, symbols: 'str') -> list:
+ """
+ The request of get transact fee rate list.
+
+ :param symbols: The symbol, like "btcusdt,htusdt". (mandatory)
+ :return: The transact fee rate list.
+ """
+ check_symbol(symbols)
+
+ params = {
+ "symbols": symbols
+ }
+
+ from huobi.service.trade.get_transact_feerate import GetTransactFeeRateService
+ return GetTransactFeeRateService(params).request(**self.__kwargs)
+
+ def sub_order_update(self, symbols: 'str', callback, error_handler=None):
+ """
+ Subscribe order changing event. If a order is created, canceled etc, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(order_update_event: 'OrderUpdateEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+ symbol_list = symbols.split(",")
+ check_symbol_list(symbol_list)
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list" : symbol_list,
+ }
+
+ from huobi.service.trade.sub_order_update_v2 import SubOrderUpdateV2Service
+ SubOrderUpdateV2Service(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def req_order_list(self, symbol: 'str', account_id: int, callback, order_states:'str',
+ order_types:'str'=None, start_date:'str'=None, end_date:'str'=None, from_id=None,
+ direct=None, size=None, client_req_id:'str'=None, error_handler=None):
+ """
+ request order list.
+
+ :param symbol: The symbol, like "btcusdt".
+ :param order_states: order status, can be one state or many state sepearted by comma, such as "submitted,partial-filled,partial-canceled,filled,canceled,created"
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(candlestick_event: 'CandlestickEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+ check_should_not_none(symbol, "symbol")
+ check_should_not_none(order_states, "states")
+ check_should_not_none(account_id, "account-d")
+ check_should_not_none(callback, "callback")
+ params = {
+ "symbol": symbol,
+ "account-id" : account_id,
+ "states" : order_states,
+ "types" : order_types,
+ "start-date" : start_date,
+ "end-date" : end_date,
+ "from": from_id,
+ "direct" : direct,
+ "size" : size,
+ "client-req-id" : client_req_id
+ }
+
+ from huobi.service.trade.req_order_list import ReqOrderListService
+ ReqOrderListService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def req_order_detail(self, order_id: 'str', callback,
+ client_req_id:'str'=None, error_handler=None):
+ """
+ Subscribe candlestick/kline event. If the candlestick/kline is updated, server will send the data to client and onReceive in callback will be called.
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ :param interval: The candlestick/kline interval, MIN1, MIN5, DAY1 etc.
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(candlestick_event: 'CandlestickEvent'):
+ pass
+ :param client_req_id: client request ID
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+ :return: No return
+ """
+ check_should_not_none(order_id, "order_id")
+ check_should_not_none(callback, "callback")
+ params = {
+ "order-id": order_id,
+ "cid": client_req_id,
+ }
+
+ from huobi.service.trade.req_order_detail import ReqOrderDetailService
+ ReqOrderDetailService(params).subscribe(callback, error_handler, **self.__kwargs)
+
+ def get_order(self, order_id: 'int') -> Order:
+ """
+ Get the details of an order.
+
+ :param order_id: The order id. (mandatory)
+ :return: The information of order.
+ """
+ check_should_not_none(order_id, "order_id")
+
+ params = {
+ "order_id": order_id,
+ }
+
+ from huobi.service.trade.get_order_by_id import GetOrderByIdService
+ return GetOrderByIdService(params).request(**self.__kwargs)
+
+ def get_order_by_client_order_id(self, client_order_id):
+ check_should_not_none(client_order_id, "clientOrderId")
+
+ params = {
+ "clientOrderId": client_order_id,
+ }
+
+ from huobi.service.trade.get_order_by_client_order_id import GetOrderByClientOrderIdService
+ return GetOrderByClientOrderIdService(params).request(**self.__kwargs)
+
+ def get_orders(self, symbol: 'str', order_state: 'OrderState', order_type: 'OrderType' = None,
+ start_date: 'str' = None, end_date: 'str' = None, start_id: 'int' = None,
+ size: 'int' = None, direct=None) -> list:
+ check_symbol(symbol)
+ check_should_not_none(order_state, "order_state")
+ start_date = format_date(start_date, "start_date")
+ end_date = format_date(end_date, "end_date")
+
+ params = {
+ "symbol" : symbol,
+ "types" : order_type,
+ "start-date" : start_date,
+ "end-date" : end_date,
+ "from" : start_id,
+ "states" : order_state,
+ "size" : size,
+ "direct" : direct
+ }
+
+ from huobi.service.trade.get_orders import GetOrdersService
+ return GetOrdersService(params).request(**self.__kwargs)
+
+ def get_open_orders(self, symbol: 'str', account_id: 'int', side: 'OrderSide' = None,
+ size: 'int' = None, from_id=None, direct=None) -> list:
+ """
+ The request of get open orders.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param account_id: account id (mandatory)
+ :param side: The order side, buy or sell. If no side defined, will return all open orders of the account. (optional)
+ :param size: The number of orders to return. Range is [1, 500]. (optional)
+ :param direct: 1:prev order by ID asc from from_id, 2:next order by ID desc from from_id
+ :param from_id: start ID for search
+ :return: The orders information.
+ """
+ check_symbol(symbol)
+ check_range(size, 1, 500, "size")
+ check_should_not_none(account_id, "account_id")
+ params = {
+ "symbol" : symbol,
+ "account-id" : account_id,
+ "side" : side,
+ "size" : size,
+ "from" : from_id,
+ "direct" : direct
+ }
+
+ from huobi.service.trade.get_open_orders import GetOpenOrdersService
+ return GetOpenOrdersService(params).request(**self.__kwargs)
+
+ def get_history_orders(self, symbol=None, start_time=None, end_time=None, size=None, direct=None)-> list:
+ """
+ Transfer Asset between Futures and Contract.
+
+ :param direct:
+ :param symbol: The target sub account uid to transfer to or from. (optional)
+ :param start_time: The crypto currency to transfer. (optional)
+ :param end_time: The amount of asset to transfer. (optional)
+ :param size: The type of transfer, need be "futures-to-pro" or "pro-to-futures" (optional)
+ :return: The Order list.
+ """
+ params = {
+ "symbol" :symbol,
+ "start-time" : start_time,
+ "end-time" : end_time,
+ "size" : size,
+ "direct" : direct
+ }
+
+ from huobi.service.trade.get_history_orders import GetHistoryOrdersService
+ return GetHistoryOrdersService(params).request(**self.__kwargs)
+
+ def get_match_result(self, symbol: 'str', order_type: 'OrderSide' = None, start_date: 'str' = None,
+ end_date: 'str' = None,
+ size: 'int' = None,
+ from_id: 'int' = None,
+ direct:'str'=None):
+ """
+ Search for the trade records of an account.
+
+ :param symbol: The symbol, like "btcusdt" (mandatory).
+ :param order_type: The types of order to include in the search (optional).
+ :param start_date: Search starts date in format yyyy-mm-dd. (optional).
+ :param end_date: Search ends date in format yyyy-mm-dd. (optional).
+ :param size: The number of orders to return, range [1-100]. (optional).
+ :param from_id: Search order id to begin with. (optional).
+ :return:
+ """
+
+ check_symbol(symbol)
+ start_date = format_date(start_date, "start_date")
+ end_date = format_date(end_date, "end_date")
+ check_range(size, 1, 100, "size")
+
+ params = {
+ "symbol" : symbol,
+ "start-date" : start_date,
+ "end-date" : end_date,
+ "types" : order_type,
+ "size" : size,
+ "from" : from_id,
+ "direct" : direct
+ }
+
+ from huobi.service.trade.get_match_results import GetMatchResultsService
+ return GetMatchResultsService(params).request(**self.__kwargs)
+
+ def get_match_results_by_order_id(self, order_id: 'int') -> list:
+ """
+ Get detail match results of an order.
+
+ :param order_id: The order id. (mandatory)
+ :return: The list of match result.
+ """
+ check_should_not_none(order_id, "order_id")
+
+ params = {
+ "order_id": order_id
+ }
+
+ from huobi.service.trade.get_match_results_by_order_id import GetMatchResultsByOrderIdService
+ return GetMatchResultsByOrderIdService(params).request(**self.__kwargs)
+
+ def order_source_desc(self, account_type):
+ default_source = "api"
+ if account_type:
+ if account_type == AccountType.MARGIN:
+ return "margin-api"
+ return default_source
+
+ def create_order_param_check(self, symbol: 'str', account_id: 'int', order_type: 'OrderType', amount: 'float',
+ price: 'float', source:'str', client_order_id=None, stop_price=None, operator=None):
+ check_symbol(symbol)
+ check_should_not_none(account_id, "account_id")
+ check_should_not_none(order_type, "order_type")
+ check_should_not_none(amount, "amount")
+ check_should_not_none(source, "source")
+
+ if order_type == OrderType.SELL_LIMIT \
+ or order_type == OrderType.BUY_LIMIT \
+ or order_type == OrderType.BUY_LIMIT_MAKER \
+ or order_type == OrderType.SELL_LIMIT_MAKER:
+ check_should_not_none(price, "price")
+ if order_type in [OrderType.SELL_MARKET, OrderType.BUY_MARKET]:
+ price = None
+
+ params = {
+ "account-id" : account_id,
+ "amount" : amount,
+ "price": price,
+ "symbol": symbol,
+ "type": order_type,
+ "source": source,
+ "client-order-id": client_order_id,
+ "stop-price": stop_price,
+ "operator": operator
+ }
+
+ return params
+
+ def create_order(self, symbol: 'str', account_id: 'int', order_type: 'OrderType', amount: 'float',
+ price: 'float', source:'str', client_order_id=None, stop_price=None, operator=None) -> int:
+ """
+ Make an order in huobi.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param account_id: Account id. (mandatory)
+ :param order_type: The order type. (mandatory)
+ :param source: The order source. (mandatory)
+ for spot, it's "api", see OrderSource.API
+ for margin, it's "margin-api", see OrderSource.MARGIN_API
+ for super margin, it's "super-margin-api", see OrderSource.SUPER_MARGIN_API
+ :param amount: The amount to buy (quote currency) or to sell (base currency). (mandatory)
+ :param price: The limit price of limit order, only needed for limit order. (mandatory for buy-limit, sell-limit, buy-limit-maker and sell-limit-maker)
+ :param client_order_id: unique Id which is user defined and must be unique in recent 24 hours
+ :param stop_price: Price for auto sell to get the max benefit
+ :param operator: the condition for stop_price, value can be "gte" or "lte", gte – greater than and equal (>=), lte – less than and equal (<=)
+ :return: The order id.
+ """
+
+ params = self.create_order_param_check(symbol, account_id, order_type, amount,
+ price, source, client_order_id, stop_price, operator)
+ from huobi.service.trade.post_create_order import PostCreateOrderService
+ return PostCreateOrderService(params).request(**self.__kwargs)
+
+ def create_spot_order(self, symbol: 'str', account_id: 'int', order_type: 'OrderType', amount: 'float',
+ price: 'float', client_order_id=None, stop_price=None,
+ operator=None) -> int:
+ order_source = OrderSource.API
+ return self.create_order(symbol=symbol, account_id=account_id, order_type=order_type, amount=amount,
+ price=price, source=order_source, client_order_id=client_order_id, stop_price=stop_price,
+ operator=operator)
+
+ def create_margin_order(self, symbol: 'str', account_id: 'int', order_type: 'OrderType', amount: 'float',
+ price: 'float', client_order_id=None, stop_price=None,
+ operator=None) -> int:
+ order_source = OrderSource.MARGIN_API
+ return self.create_order(symbol=symbol, account_id=account_id, order_type=order_type, amount=amount,
+ price=price, source=order_source, client_order_id=client_order_id,
+ stop_price=stop_price,
+ operator=operator)
+
+ def create_super_margin_order(self, symbol: 'str', account_id: 'int', order_type: 'OrderType', amount: 'float',
+ price: 'float', client_order_id=None, stop_price=None,
+ operator=None) -> int:
+ order_source = OrderSource.SUPER_MARGIN_API
+ return self.create_order(symbol=symbol, account_id=account_id, order_type=order_type, amount=amount,
+ price=price, source=order_source, client_order_id=client_order_id,
+ stop_price=stop_price,
+ operator=operator)
+
+ def cancel_order(self, symbol, order_id):
+ check_symbol(symbol)
+ check_should_not_none(order_id, "order_id")
+
+ params = {
+ "order_id" : order_id
+ }
+
+ from huobi.service.trade.post_cancel_order import PostCancelOrderService
+ return PostCancelOrderService(params).request(**self.__kwargs)
+
+ def cancel_orders(self, symbol, order_id_list)->BatchCancelResult:
+ """
+ Submit cancel request for cancelling multiple orders.
+
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param order_id_list: The list of order id. the max size is 50. (mandatory)
+ :return: No return
+ """
+ check_symbol(symbol)
+ check_should_not_none(order_id_list, "order_id_list")
+ check_list(order_id_list, 1, 50, "order_id_list")
+
+ string_list = list()
+ for order_id in order_id_list:
+ string_list.append(str(order_id))
+
+ params = {
+ "order-ids" : string_list
+ }
+
+ from huobi.service.trade.post_batch_cancel_order import PostBatchCancelOrderService
+ return PostBatchCancelOrderService(params).request(**self.__kwargs)
+
+ def cancel_open_orders(self, account_id, symbols: 'str'=None , side=None, size=None)->BatchCancelCount:
+ """
+ Request to cancel open orders.
+
+ :param symbols: The symbol, like "btcusdt".
+ :param account_type: Account type. (mandatory)
+ :param side: The order side, buy or sell. If no side defined, will cancel all open orders of the account. (optional)
+ :param size: The number of orders to cancel. Range is [1, 100]. (optional)
+ :return: Status of batch cancel result.
+ """
+ check_should_not_none(account_id, "account_id")
+
+ params = {
+ "account-id": account_id,
+ "symbol" : symbols,
+ "side" : side,
+ "size" : size
+ }
+
+ from huobi.service.trade.post_batch_cancel_open_order import PostBatchCancelOpenOrderService
+ return PostBatchCancelOpenOrderService(params).request(**self.__kwargs)
+
+ def cancel_client_order(self, client_order_id)->int:
+ """
+ Request to cancel open orders.
+
+ :param client_order_id: user defined unique order id
+ """
+ check_should_not_none(client_order_id, "client-order-id")
+
+ params = {
+ "client-order-id" : client_order_id
+ }
+
+ from huobi.service.trade.post_cancel_client_order import PostCancelClientOrderService
+ return PostCancelClientOrderService(params).request(**self.__kwargs)
+
+ def transfer_between_futures_and_pro(self, currency: 'str', amount: 'float',
+ transfer_type: 'TransferFuturesPro')-> int:
+ """
+ Transfer Asset between Futures and Contract.
+
+ :param sub_uid: The target sub account uid to transfer to or from. (mandatory)
+ :param currency: The crypto currency to transfer. (mandatory)
+ :param amount: The amount of asset to transfer. (mandatory)
+ :param transfer_type: The type of transfer, need be "futures-to-pro" or "pro-to-futures" (mandatory)
+ :return: The order id.
+ """
+ check_currency(currency)
+ check_should_not_none(currency, "currency")
+ check_should_not_none(amount, "amount")
+ check_should_not_none(transfer_type, "transfer_type")
+ params = {
+ "currency" : currency,
+ "amount" : amount,
+ "type" : transfer_type
+
+ }
+
+ from huobi.service.trade.post_transfer_futures_pro import PostTransferFuturesProService
+ return PostTransferFuturesProService(params).request(**self.__kwargs)
+
+ def batch_create_order(self, order_config_list) -> int:
+ """
+ Make an order in huobi.
+ :param order_config_list: order config list, it can batch create orders, and each order config check as below
+ : items as below
+ :param symbol: The symbol, like "btcusdt". (mandatory)
+ :param account_type: Account type. (mandatory)
+ :param order_type: The order type. (mandatory)
+ :param amount: The amount to buy (quote currency) or to sell (base currency). (mandatory)
+ :param price: The limit price of limit order, only needed for limit order. (mandatory for buy-limit, sell-limit, buy-limit-maker and sell-limit-maker)
+ :param client_order_id: unique Id which is user defined and must be unique in recent 24 hours
+ :param stop_price: Price for auto sell to get the max benefit
+ :param operator: the condition for stop_price, value can be "gte" or "lte", gte – greater than and equal (>=), lte – less than and equal (<=)
+ :return: The order id.
+ """
+
+ check_should_not_none(order_config_list, "order_config_list")
+ check_list(order_config_list, 1, 10, "create order config list")
+
+ new_config_list = list()
+ for item in order_config_list:
+ new_item = self.create_order_param_check(
+ item.get("symbol", None),
+ item.get("account_id", None),
+ item.get("order_type", None),
+ item.get("amount", None),
+ item.get("price", None),
+ item.get("source", None),
+ item.get("client_order_id", None),
+ item.get("stop-price", None),
+ item.get("operator", None))
+
+ new_config_list.append(new_item)
+
+ from huobi.service.trade.post_batch_create_order import PostBatchCreateOrderService
+ return PostBatchCreateOrderService(new_config_list).request(**self.__kwargs)
+
+ def sub_trade_clearing(self, symbols: 'str', callback, error_handler=None):
+ """
+ Subscribe trade clearing by symbol
+
+ :param symbols: The symbols, like "btcusdt". Use comma to separate multi symbols, like "btcusdt,ethusdt".
+ "*" for all symbols
+ :param callback: The implementation is required. onReceive will be called if receive server's update.
+ example: def callback(price_depth_event: 'PriceDepthEvent'):
+ pass
+ :param error_handler: The error handler will be called if subscription failed or error happen between client and Huobi server
+ example: def error_handler(exception: 'HuobiApiException')
+ pass
+
+ :return: No return
+ """
+ check_should_not_none(symbols, "symbols")
+ symbol_list = symbols.split(",")
+ if ("*" in symbol_list):
+ symbol_list = ["*"]
+ else:
+ check_symbol_list(symbol_list)
+
+ check_should_not_none(callback, "callback")
+
+ params = {
+ "symbol_list": symbol_list,
+ }
+
+ from huobi.service.trade.sub_trade_clearing_v2 import SubTradeClearingV2Service
+ SubTradeClearingV2Service(params).subscribe(callback, error_handler, **self.__kwargs)
diff --git a/huobi/client/wallet.py b/huobi/client/wallet.py
new file mode 100644
index 0000000..519b822
--- /dev/null
+++ b/huobi/client/wallet.py
@@ -0,0 +1,179 @@
+from huobi.utils.input_checker import *
+from huobi.model.wallet import *
+
+
+class WalletClient(object):
+
+ def __init__(self, **kwargs):
+ """
+ Create the request client instance.
+ :param kwargs: The option of request connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: The URL name like "https://api.huobi.pro".
+ init_log: to init logger
+ """
+ self.__kwargs = kwargs
+
+ def get_deposit_withdraw(self, op_type: 'str', currency: 'str' = None, from_id: 'int' = None, size: 'int' = None,
+ direct: 'str' = None) -> list:
+ """
+ Get the withdraw records of an account.
+
+ :param currency: The currency, like "btc". (optional)
+ :param from_id: The beginning withdraw record id. (optional)
+ :param op_type: deposit or withdraw, see defination DepositWithdraw (mandatory)
+ :param size: The size of record. (optional)
+ :param direct: "prev" is order by asc, "next" is order by desc, default as "prev"(optional)
+ :return: The list of withdraw records.
+ """
+ check_should_not_none(op_type, "operate type")
+
+ params = {
+ "currency": currency,
+ "type": op_type,
+ "from": from_id,
+ "direct": direct,
+ "size": size
+ }
+
+ from huobi.service.wallet.get_deposit_withdraw import GetDepositWithdrawService
+ return GetDepositWithdrawService(params).request(**self.__kwargs)
+
+ def post_create_withdraw(self, address: 'str', amount: 'float', currency: 'str', fee: 'float',
+ chain: 'str' = None, address_tag: 'str' = None) -> int:
+ """
+ Submit a request to withdraw some asset from an account.
+
+ :param address: The destination address of this withdraw. (mandatory)
+ :param amount: The amount of currency to withdraw. (mandatory)
+ :param currency: The crypto currency to withdraw. (mandatory)
+ :param fee: The fee to pay with this withdraw. (mandatory)
+ :param address_tag: A tag specified for this address. (optional)
+ :param chain: set as "usdt" to withdraw USDT to OMNI, set as "trc20usdt" to withdraw USDT to TRX. (optional)
+ :return: Withdraw id
+ """
+ check_symbol(currency)
+ check_should_not_none(address, "address")
+ check_should_not_none(amount, "amount")
+ check_should_not_none(fee, "fee")
+
+ params = {
+ "currency": currency,
+ "address": address,
+ "amount": amount,
+ "fee": fee,
+ "chain": chain,
+ "addr-tag": address_tag
+ }
+
+ from huobi.service.wallet.post_create_withdraw import PostCreateWithdrawService
+ return PostCreateWithdrawService(params).request(**self.__kwargs)
+
+ def post_cancel_withdraw(self, withdraw_id: 'int') -> int:
+ """
+ Cancel an withdraw request.
+
+ :param withdraw_id: withdraw id (mandatory)
+ :return: No return.
+ """
+ params = {
+ "withdraw-id": withdraw_id
+ }
+
+ from huobi.service.wallet.post_cancel_withdraw import PostCancelWithdrawService
+ return PostCancelWithdrawService(params).request(**self.__kwargs)
+
+ def get_account_deposit_address(self, currency: 'str') -> list:
+ """
+ Get deposit address of corresponding chain, for a specific crypto currency (except IOTA)
+
+ :param currency: The currency, like "btc". (optional)
+ :return:
+ """
+ check_should_not_none(currency, "currency")
+
+ params = {
+ "currency": currency
+ }
+
+ from huobi.service.wallet.get_account_deposit_address import GetAccountDepositAddressService
+ return GetAccountDepositAddressService(params).request(**self.__kwargs)
+
+ def get_account_withdraw_quota(self, currency: 'str') -> list:
+ """
+ Get the withdraw quota for currencies
+
+ :param currency: The currency, like "btc". (mandatory)
+ :return:
+ """
+ check_should_not_none(currency, "currency")
+
+ params = {
+ "currency": currency,
+ }
+
+ from huobi.service.wallet.get_account_withdraw_quota import GetAccountWithdrawQuotaService
+ return GetAccountWithdrawQuotaService(params).request(**self.__kwargs)
+
+ def get_sub_user_deposit_history(self, sub_uid: 'int', currency: 'str' = None,
+ start_time: 'int' = None, end_time: 'int' = None,
+ sort: 'str' = None, limit: 'int' = None, from_id: 'int' = None) -> DepositHistory:
+ """
+ Parent get sub user depoist history.
+
+ :param sub_uid: Sub user id. (mandatory)
+ :param currency: Cryptocurrency.
+ :param start_time: Farthest time
+ :param end_time: Nearest time
+ :param sort: Sorting order
+ :param limit: Maximum number of items in one page
+ :param from_id: First record Id in this query
+ """
+ check_should_not_none(sub_uid, "sub_uid")
+
+ params = {
+ "subUid": sub_uid,
+ "currency": currency,
+ "startTime": start_time,
+ "endTime": end_time,
+ "sort": sort,
+ "limit": limit,
+ "fromId": from_id
+ }
+
+ from huobi.service.wallet.get_sub_user_deposit_history import GetSubUserDepositHistoryService
+ return GetSubUserDepositHistoryService(params).request(**self.__kwargs)
+
+ def get_sub_user_deposit_address(self, sub_uid: 'int', currency: 'str') -> list:
+ """
+ Parent get sub user deposit address
+
+ :param sub_uid: Sub user id
+ :param currency: Cryptocurrency, like "btc". (mandatory)
+ :return:
+ """
+
+ check_should_not_none(sub_uid, "subUid")
+ check_should_not_none(currency, "currency")
+ params = {
+ "subUid": sub_uid,
+ "currency": currency
+ }
+
+ from huobi.service.wallet.get_sub_user_deposit_address import GetSubUserDepositAddressService
+ return GetSubUserDepositAddressService(params).request(**self.__kwargs)
+
+ def get_account_withdraw_address(self, currency: 'str', chain: 'str'=None, note: 'str'=None, limit: 'int' = 100,
+ fromid: 'int' = None):
+ check_should_not_none(currency, "currency")
+ params = {
+ "currency": currency,
+ "chain": chain,
+ "note": note,
+ "limit": limit,
+ "fromid": fromid
+ }
+ from huobi.service.wallet.get_account_withdraw_address import GetAccountWithdrawAddressService
+ return GetAccountWithdrawAddressService(params).request(**self.__kwargs)
+
diff --git a/huobi/connection/__init__.py b/huobi/connection/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/connection/impl/__init__.py b/huobi/connection/impl/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/huobi/connection/impl/__init__.py
@@ -0,0 +1 @@
+
diff --git a/huobi/connection/impl/private_def.py b/huobi/connection/impl/private_def.py
new file mode 100644
index 0000000..a64c805
--- /dev/null
+++ b/huobi/connection/impl/private_def.py
@@ -0,0 +1,11 @@
+
+
+class ConnectionState:
+ IDLE = 0
+ CONNECTED = 1
+ WAIT_RECONNECT = 2
+ CLOSED_ON_ERROR = 3
+ CLOSED = 4
+
+CONNECT_HEART_BEAT_LIMIT_MS = 60000 # max interval between two package
+RECONNECT_AFTER_TIME_MS = 63000 # if not need connect immediately, it will enter delay connect status and will connect after setting times
\ No newline at end of file
diff --git a/huobi/connection/impl/restapi_invoker.py b/huobi/connection/impl/restapi_invoker.py
new file mode 100644
index 0000000..6c23d5f
--- /dev/null
+++ b/huobi/connection/impl/restapi_invoker.py
@@ -0,0 +1,94 @@
+import requests
+from huobi.exception.huobi_api_exception import HuobiApiException
+from huobi.utils.etf_result import etf_result_check
+from huobi.utils import *
+import time
+
+from huobi.utils.print_mix_object import TypeCheck
+
+session = requests.Session()
+
+def check_response(dict_data):
+ status = dict_data.get("status", None)
+ code = dict_data.get("code", None)
+ success = dict_data.get("success", None)
+ if status and len(status):
+ if TypeCheck.is_basic(status): # for normal case
+ if status == "error":
+ err_code = dict_data.get("err-code", 0)
+ err_msg = dict_data.get("err-msg", "")
+ raise HuobiApiException(HuobiApiException.EXEC_ERROR,
+ "[Executing] " + str(err_code) + ": " + err_msg)
+ elif status != "ok":
+ raise HuobiApiException(HuobiApiException.RUNTIME_ERROR,
+ "[Invoking] Response is not expected: " + status)
+ elif TypeCheck.is_dict(status): # for https://status.huobigroup.com/api/v2/summary.json in example example/generic/get_system_status.py
+ if dict_data.get("page") and dict_data.get("components"):
+ pass
+ else:
+ raise HuobiApiException(HuobiApiException.EXEC_ERROR,
+ "[Executing] System is in maintenances")
+ elif code:
+ code_int = int(code)
+ if code_int != 200:
+ err_code = dict_data.get("code", 0)
+ err_msg = dict_data.get("message", "")
+ raise HuobiApiException(HuobiApiException.EXEC_ERROR,
+ "[Executing] " + str(err_code) + ": " + err_msg)
+ elif success is not None:
+ if bool(success) is False:
+ err_code = etf_result_check(dict_data.get("code"))
+ err_msg = dict_data.get("message", "")
+ if err_code == "":
+ raise HuobiApiException(HuobiApiException.EXEC_ERROR, "[Executing] " + err_msg)
+ else:
+ raise HuobiApiException(HuobiApiException.EXEC_ERROR, "[Executing] " + str(err_code) + ": " + err_msg)
+ else:
+ raise HuobiApiException(HuobiApiException.RUNTIME_ERROR, "[Invoking] Status cannot be found in response.")
+
+
+def call_sync(request, is_checked=False):
+ if request.method == "GET":
+ # print("call_sync url : " , request.host + request.url)
+ response = session.get(request.host + request.url, headers=request.header)
+ if is_checked is True:
+ return response.text
+ #dict_data = json.loads(response.text, encoding="utf-8")
+ dict_data = json.loads(response.text)
+ # print("call_sync === recv data : ", dict_data)
+ check_response(dict_data)
+ return request.json_parser(dict_data)
+
+ elif request.method == "POST":
+ response = session.post(request.host + request.url, data=json.dumps(request.post_body), headers=request.header)
+ dict_data = json.loads(response.text, encoding="utf-8")
+ # print("call_sync === recv data : ", dict_data)
+ check_response(dict_data)
+ return request.json_parser(dict_data)
+
+def call_sync_perforence_test(request, is_checked=False):
+ if request.method == "GET":
+ inner_start_time = time.time()
+ # print("call_sync_perforence_test url : ", request.host + request.url)
+ response = session.get(request.host + request.url, headers=request.header)
+ #print("call_sync_perforence_test data :", response.text)
+ inner_end_time = time.time()
+ cost_manual = round(inner_end_time - inner_start_time, 6)
+ req_cost = response.elapsed.total_seconds()
+ if is_checked is True:
+ return response.text
+ dict_data = json.loads(response.text, encoding="utf-8")
+ # print("call_sync === recv data : ", dict_data)
+ check_response(dict_data)
+ return request.json_parser(dict_data), req_cost, cost_manual
+
+ elif request.method == "POST":
+ inner_start_time = time.time()
+ response = session.post(request.host + request.url, data=json.dumps(request.post_body), headers=request.header)
+ inner_end_time = time.time()
+ cost_manual = round(inner_end_time - inner_start_time, 6)
+ req_cost = response.elapsed.total_seconds()
+ dict_data = json.loads(response.text, encoding="utf-8")
+ # print("call_sync === recv data : ", dict_data)
+ check_response(dict_data)
+ return request.json_parser(dict_data), req_cost, cost_manual
diff --git a/huobi/connection/impl/restapi_request.py b/huobi/connection/impl/restapi_request.py
new file mode 100644
index 0000000..d6e029f
--- /dev/null
+++ b/huobi/connection/impl/restapi_request.py
@@ -0,0 +1,11 @@
+
+class RestApiRequest(object):
+
+ def __init__(self):
+ self.method = ""
+ self.url = ""
+ self.host = ""
+ self.post_body = ""
+ self.header = dict()
+ self.json_parser = None
+
diff --git a/huobi/connection/impl/websocket_manage.py b/huobi/connection/impl/websocket_manage.py
new file mode 100644
index 0000000..72bc10c
--- /dev/null
+++ b/huobi/connection/impl/websocket_manage.py
@@ -0,0 +1,281 @@
+import threading
+import websocket
+import gzip
+import ssl
+import logging
+import urllib.parse
+
+from huobi.constant import *
+from huobi.utils import *
+from huobi.exception.huobi_api_exception import HuobiApiException
+from huobi.connection.impl.private_def import ConnectionState
+
+# Key: original_connection, Value: connection
+websocket_connection_handler = dict()
+
+
+def on_message(original_connection, message):
+ websocket_connection = websocket_connection_handler[original_connection]
+ websocket_connection.on_message(message)
+ return
+
+
+def on_error(original_connection, error):
+ websocket_connection = websocket_connection_handler[original_connection]
+ websocket_connection.on_failure(error)
+
+
+def on_close(original_connection):
+ websocket_connection = websocket_connection_handler[original_connection]
+ websocket_connection.on_close()
+
+
+def on_open(original_connection):
+ websocket_connection = websocket_connection_handler[original_connection]
+ websocket_connection.on_open(original_connection)
+
+
+connection_id = 0
+
+
+def websocket_func(*args):
+ try:
+ websocket_manage = args[0]
+ websocket_manage.original_connection = websocket.WebSocketApp(websocket_manage.url,
+ on_message=on_message,
+ on_error=on_error,
+ on_close=on_close)
+ global websocket_connection_handler
+ websocket_connection_handler[websocket_manage.original_connection] = websocket_manage
+ websocket_manage.logger.info("[Sub][" + str(websocket_manage.id) + "] Connecting...")
+ websocket_manage.original_connection.on_open = on_open
+ websocket_manage.original_connection.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
+ websocket_manage.logger.info("[Sub][" + str(websocket_manage.id) + "] Connection event loop down")
+ if websocket_manage.state == ConnectionState.CONNECTED:
+ websocket_manage.state = ConnectionState.IDLE
+ except Exception as ex:
+ print(ex)
+
+class WebsocketManage:
+
+ def __init__(self, api_key, secret_key, uri, request):
+ self.__thread = None
+ self.__market_url = HUOBI_WEBSOCKET_URI_PRO + "/ws"
+ self.__trading_url = HUOBI_WEBSOCKET_URI_PRO + "/ws/" + request.api_version
+ self.__mbp_feed_url = HUOBI_WEBSOCKET_URI_PRO + "/feed"
+ self.__api_key = api_key
+ self.__secret_key = secret_key
+ self.request = request
+ self.reconnect_at = 0
+ self.original_connection = None
+ self.last_receive_time = 0
+ self.logger = logging.getLogger("huobi-client")
+ self.state = ConnectionState.IDLE
+ global connection_id
+ connection_id += 1
+ self.id = connection_id
+ host = urllib.parse.urlparse(uri).hostname
+ if host.find("api") == 0:
+ self.__market_url = "wss://" + host + "/ws"
+ self.__mbp_feed_url = "wss://" + host + "/feed"
+ self.__trading_url = "wss://" + host + "/ws/" + request.api_version
+ else:
+ self.__market_url = "wss://" + host + "/api/ws"
+ self.__mbp_feed_url = "wss://" + host + "/feed"
+ self.__trading_url = "wss://" + host + "/ws/" + request.api_version
+
+ if request.is_trading:
+ self.url = self.__trading_url
+ elif request.is_mbp_feed:
+ self.url = self.__mbp_feed_url
+ else:
+ self.url = self.__market_url
+
+ def close_and_wait_reconnect(self, delay_in_ms):
+ if self.original_connection is not None:
+ self.original_connection.close()
+ self.original_connection = None
+ self.state = ConnectionState.WAIT_RECONNECT
+ self.reconnect_at = + delay_in_ms
+ self.logger.warning("[Sub][%d] Lost connectiong for %d ms, will try reconnecting " % (self.id, self.reconnect_at))
+
+ def re_connect(self):
+ if get_current_timestamp() > self.reconnect_at:
+ self.logger.info("[Sub][%d] Reconnecting ... " % self.id)
+ self.connect()
+
+ def connect(self):
+ if self.state == ConnectionState.CONNECTED:
+ self.logger.info("[Sub][" + str(self.id) + "] Already connected")
+ else:
+ self.__thread = threading.Thread(target=websocket_func, args=[self])
+ self.__thread.start()
+
+ def send(self, data):
+ # print("Send Data : " + data)
+ self.original_connection.send(data)
+
+ def close(self):
+ self.original_connection.close()
+ del websocket_connection_handler[self.original_connection]
+ self.state = ConnectionState.CLOSED
+ self.logger.info("[Sub][" + str(self.id) + "] Closing normally")
+
+ def on_open(self, original_connection):
+ self.logger.info("[Sub][" + str(self.id) + "] Connected to server")
+ self.original_connection = original_connection
+ self.last_receive_time = get_current_timestamp()
+ self.state = ConnectionState.CONNECTED
+ if self.request.is_trading:
+ try:
+ if self.request.api_version == ApiVersion.VERSION_V1:
+ builder = UrlParamsBuilder()
+ create_signature(self.__api_key, self.__secret_key,
+ "GET", self.url, builder)
+ builder.put_url("op", "auth")
+ self.send(builder.build_url_to_json())
+ elif self.request.api_version == ApiVersion.VERSION_V2:
+ builder = UrlParamsBuilder()
+ create_signature_v2(self.__api_key, self.__secret_key,
+ "GET", self.url, builder)
+ self.send(builder.build_url_to_json())
+ else:
+ self.on_error("api version for create the signature fill failed")
+
+ except Exception as e:
+ self.on_error("Unexpected error when create the signature: " + str(e))
+ else:
+ if self.request.subscription_handler is not None:
+ self.request.subscription_handler(self)
+ return
+
+ def on_error(self, error_message):
+ if self.request.error_handler is not None:
+ exception = HuobiApiException(HuobiApiException.SUBSCRIPTION_ERROR, error_message)
+ self.request.error_handler(exception)
+ self.logger.error("[Sub][" + str(self.id) + "] " + str(error_message))
+
+ def on_failure(self, error):
+ self.on_error("Unexpected error: " + str(error))
+ self.close_on_error()
+
+ def on_message(self, message):
+ self.last_receive_time = get_current_timestamp()
+ if isinstance(message, (str)): # V2
+ # print("RX string : ", message)
+ dict_data = json.loads(message)
+ elif isinstance(message, (bytes)): # V1
+ # print("RX bytes: " + gzip.decompress(message).decode("utf-8"))
+ dict_data = json.loads(gzip.decompress(message).decode("utf-8"))
+ else:
+ print("RX unknow type : ", type(message))
+ return
+
+ status_outer = dict_data.get("status", "")
+ err_code_outer = dict_data.get("err-code", 0)
+ op_outer = dict_data.get("op", "")
+ action_outer = dict_data.get("action", "")
+ ch_outer = dict_data.get("ch", "")
+ rep_outer = dict_data.get("rep", "")
+ ping_market_outer = int(dict_data.get("ping", 0))
+ if status_outer and len(status_outer) and status_outer != "ok":
+ error_code = dict_data.get("err-code", "Unknown error")
+ error_msg = dict_data.get("err-msg", "Unknown error")
+ self.on_error(error_code + ": " + error_msg)
+ elif err_code_outer and int(err_code_outer) != 0:
+ error_code = dict_data.get("err-code", "Unknown error")
+ error_msg = dict_data.get("err-msg", "Unknown error")
+ self.on_error(error_code + ": " + error_msg)
+ elif op_outer and len(op_outer): # for V1
+ if op_outer == "notify":
+ self.__on_receive(dict_data)
+ elif op_outer == "ping":
+ #print("******** receive trade ping pong ********", dict_data)
+ ping_ts = dict_data.get("ts", 0)
+ self.__process_ping_on_trading_line(ping_ts)
+ elif op_outer == "auth":
+ if self.request.subscription_handler is not None:
+ self.request.subscription_handler(self)
+ elif op_outer == "req":
+ self.__on_receive(dict_data)
+ elif action_outer and len(action_outer): # for V2
+ if action_outer == "ping":
+ action_data = dict_data.get("data")
+ ping_ts = action_data.get("ts")
+ self.__process_ping_on_v2_trade(ping_ts)
+ elif action_outer == "sub":
+ action_code = dict_data.get("code", -1)
+ if action_code == 200:
+ logging.info("subscribe ACK received")
+ else:
+ logging.error("receive error data : " + message)
+ elif action_outer == "req": #
+ action_code = dict_data.get("code", -1)
+ if action_code == 200:
+ logging.info("signature ACK received")
+ if self.request.subscription_handler is not None:
+ self.request.subscription_handler(self)
+ else:
+ logging.error("receive error data : " + message)
+ elif action_outer == "push":
+ action_data = dict_data.get("data")
+ if action_data:
+ self.__on_receive(dict_data)
+ else:
+ logging.error("receive error push data : " + message)
+
+ elif ch_outer and len(ch_outer):
+ self.__on_receive(dict_data)
+ elif rep_outer and len(rep_outer):
+ self.__on_receive(dict_data)
+ elif ping_market_outer:
+ #print("******** receive market ping pong ********", dict_data)
+ ping_ts = ping_market_outer
+ self.__process_ping_on_market_line(ping_ts)
+ else:
+ #print("unknown data process, RX: ", gzip.decompress(message).decode("utf-8"))
+ pass
+
+ def __on_receive(self, dict_data):
+ res = None
+ try:
+ if self.request.json_parser is not None:
+ res = self.request.json_parser(dict_data)
+ except Exception as e:
+ self.on_error("Failed to parse server's response: " + str(e))
+
+ try:
+ if self.request.update_callback is not None:
+ self.request.update_callback(res)
+ except Exception as e:
+ self.on_error("Process error: " + str(e)
+ + " You should capture the exception in your error handler")
+
+ # websocket request will close the connection after receive
+ if self.request.auto_close:
+ self.close()
+
+ def __process_ping_on_trading_line(self, ping_ts):
+ #print("### __process_ping_on_trading_line ###")
+ #self.send("{\"op\":\"pong\",\"ts\":" + str(get_current_timestamp()) + "}")
+ PrintBasic.print_basic(ping_ts, "response time")
+ self.send("{\"op\":\"pong\",\"ts\":" + str(ping_ts) + "}")
+ return
+
+ def __process_ping_on_market_line(self, ping_ts):
+ #print("### __process_ping_on_market_line ###")
+ #self.send("{\"pong\":" + str(get_current_timestamp()) + "}")
+ PrintBasic.print_basic(ping_ts, "response time")
+ self.send("{\"pong\":" + str(ping_ts) + "}")
+ return
+
+ def __process_ping_on_v2_trade(self, ping_ts):
+ # PrintDate.timestamp_to_date(ping_ts)
+ self.send("{\"action\": \"pong\",\"data\": {\"ts\": " + str(ping_ts) +"}}")
+ return
+
+ def close_on_error(self):
+ if self.original_connection is not None:
+ self.original_connection.close()
+ self.state = ConnectionState.CLOSED_ON_ERROR
+ self.logger.error("[Sub][" + str(self.id) + "] Connection is closing due to error")
diff --git a/huobi/connection/impl/websocket_request.py b/huobi/connection/impl/websocket_request.py
new file mode 100644
index 0000000..9efd1de
--- /dev/null
+++ b/huobi/connection/impl/websocket_request.py
@@ -0,0 +1,14 @@
+from huobi.constant import ApiVersion
+
+
+class WebsocketRequest(object):
+
+ def __init__(self):
+ self.subscription_handler = None
+ self.auto_close = False # close connection after receive data, for subscribe set False, for request set True
+ self.is_trading = False
+ self.is_mbp_feed = False
+ self.error_handler = None
+ self.json_parser = None
+ self.update_callback = None
+ self.api_version = ApiVersion.VERSION_V1 # v1 as default
diff --git a/huobi/connection/impl/websocket_watchdog.py b/huobi/connection/impl/websocket_watchdog.py
new file mode 100644
index 0000000..f755def
--- /dev/null
+++ b/huobi/connection/impl/websocket_watchdog.py
@@ -0,0 +1,67 @@
+import threading
+import logging
+from apscheduler.schedulers.blocking import BlockingScheduler
+
+from huobi.connection.impl.private_def import *
+from huobi.utils.time_service import get_current_timestamp
+
+
+def watch_dog_job(*args):
+ watch_dog_obj = args[0]
+
+ for idx, websocket_manage in enumerate(watch_dog_obj.websocket_manage_list):
+ if websocket_manage.request.auto_close: # setting auto close no need reconnect
+ pass
+ elif websocket_manage.state == ConnectionState.CONNECTED:
+ if watch_dog_obj.is_auto_connect:
+ ts = get_current_timestamp() - websocket_manage.last_receive_time
+ if ts > watch_dog_obj.heart_beat_limit_ms:
+ watch_dog_obj.logger.warning("[Sub][" + str(websocket_manage.id) + "] No response from server")
+ websocket_manage.close_and_wait_reconnect(watch_dog_obj.wait_reconnect_millisecond())
+ elif websocket_manage.state == ConnectionState.WAIT_RECONNECT:
+ watch_dog_obj.logger.warning("[Sub] call re_connect")
+ websocket_manage.re_connect()
+ pass
+ elif websocket_manage.state == ConnectionState.CLOSED_ON_ERROR:
+ if watch_dog_obj.is_auto_connect:
+ websocket_manage.close_and_wait_reconnect(watch_dog_obj.reconnect_after_ms)
+ pass
+
+
+class WebSocketWatchDog(threading.Thread):
+ mutex = threading.Lock()
+ websocket_manage_list = list()
+
+ def __init__(self, is_auto_connect=True, heart_beat_limit_ms=CONNECT_HEART_BEAT_LIMIT_MS, reconnect_after_ms=RECONNECT_AFTER_TIME_MS):
+ threading.Thread.__init__(self)
+ self.is_auto_connect = is_auto_connect
+ self.heart_beat_limit_ms = heart_beat_limit_ms
+ self.reconnect_after_ms = reconnect_after_ms if reconnect_after_ms > heart_beat_limit_ms else heart_beat_limit_ms
+ self.logger = logging.getLogger("huobi-client")
+ self.scheduler = BlockingScheduler()
+ self.scheduler.add_job(watch_dog_job, "interval", max_instances=10, seconds=1, args=[self])
+ self.start()
+
+ def run(self):
+ self.scheduler.start()
+
+ def on_connection_created(self, websocket_manage):
+ self.mutex.acquire()
+ self.websocket_manage_list.append(websocket_manage)
+ self.mutex.release()
+
+ def on_connection_closed(self, websocket_manage):
+ self.mutex.acquire()
+ self.websocket_manage_list.remove(websocket_manage)
+ self.mutex.release()
+
+ # calculate next reconnect time
+ def wait_reconnect_millisecond(self):
+ wait_millisecond = int(self.reconnect_after_ms - self.heart_beat_limit_ms)
+ now_ms = get_current_timestamp()
+ wait_millisecond = wait_millisecond if wait_millisecond else 1000
+ # job loop after 1 second
+ return (wait_millisecond + now_ms)
+
+
+
diff --git a/huobi/connection/restapi_sync_client.py b/huobi/connection/restapi_sync_client.py
new file mode 100644
index 0000000..22e2207
--- /dev/null
+++ b/huobi/connection/restapi_sync_client.py
@@ -0,0 +1,154 @@
+import logging
+
+from huobi.connection.impl.restapi_invoker import call_sync, call_sync_perforence_test
+from huobi.connection.impl.restapi_request import RestApiRequest
+from huobi.constant import *
+from huobi.utils import *
+
+from huobi.exception.huobi_api_exception import HuobiApiException
+
+
+
+class RestApiSyncClient(object):
+
+ def __init__(self, **kwargs):
+ """
+ Create the request client instance.
+ :param kwargs: The option of request connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: The URL name like "https://api.huobi.pro".
+ performance_test: for performance test
+ init_log: to init logger
+ """
+ self.__api_key = kwargs.get("api_key", None)
+ self.__secret_key = kwargs.get("secret_key", None)
+ self.__server_url = kwargs.get("url", get_default_server_url(None))
+ self.__init_log = kwargs.get("init_log", None)
+ self.__performance_test = kwargs.get("performance_test", None)
+ if self.__init_log and self.__init_log:
+ logger = logging.getLogger("huobi-client")
+ logger.setLevel(level=logging.INFO)
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
+ logger.addHandler(handler)
+
+ def __create_request_by_get(self, url, builder):
+ request = RestApiRequest()
+ request.method = "GET"
+ request.host = self.__server_url
+ request.header.update({'Content-Type': 'application/json'})
+ request.url = url + builder.build_url()
+ return request
+
+ def __create_request_by_post_with_signature(self, url, builder):
+ request = RestApiRequest()
+ request.method = "POST"
+ request.host = self.__server_url
+ create_signature(self.__api_key, self.__secret_key, request.method, request.host + url, builder)
+ request.header.update({'Content-Type': 'application/json'})
+ if (len(builder.post_list)): # specify for case : /v1/order/batch-orders
+ request.post_body = builder.post_list
+ else:
+ request.post_body = builder.post_map
+ request.url = url + builder.build_url()
+ return request
+
+ def __create_request_by_get_with_signature(self, url, builder):
+ request = RestApiRequest()
+ request.method = "GET"
+ request.host = self.__server_url
+ create_signature(self.__api_key, self.__secret_key, request.method, request.host + url, builder)
+ request.header.update({"Content-Type": "application/x-www-form-urlencoded"})
+ request.url = url + builder.build_url()
+ return request
+
+ def create_request(self, method, url, params, parse):
+ builder = UrlParamsBuilder()
+ if params and len(params):
+ if method in [HttpMethod.GET, HttpMethod.GET_SIGN]:
+ for key, value in params.items():
+ builder.put_url(key, value)
+ elif method in [HttpMethod.POST, HttpMethod.POST_SIGN]:
+ for key, value in params.items():
+ builder.put_post(key, value)
+ else:
+ raise HuobiApiException(HuobiApiException.EXEC_ERROR,
+ "[error] undefined HTTP method")
+
+ if method == HttpMethod.GET:
+ request = self.__create_request_by_get(url, builder)
+ elif method == HttpMethod.GET_SIGN:
+ request = self.__create_request_by_get_with_signature(url, builder)
+ elif method == HttpMethod.POST_SIGN:
+ request = self.__create_request_by_post_with_signature(url, builder)
+ elif method == HttpMethod.POST:
+ request = self.__create_request_by_post_with_signature(url, builder)
+ else:
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] " + method + " is invalid http method")
+
+ request.json_parser = parse
+
+ return request
+
+ """
+ for post batch operation, such as batch create orders[ /v1/order/batch-orders ]
+ """
+ def create_request_post_batch(self, method, url, params, parse):
+ builder = UrlParamsBuilder()
+ if params and len(params):
+ if method in [HttpMethod.POST, HttpMethod.POST_SIGN]:
+ if isinstance(params, list):
+ builder.post_list = params
+ else:
+ raise HuobiApiException(HuobiApiException.EXEC_ERROR,
+ "[error] undefined HTTP method")
+
+ request = self.__create_request_by_post_with_signature(url, builder)
+ request.json_parser = parse
+
+ return request
+
+ def request_process(self, method, url, params, parse):
+ if self.__performance_test is not None and self.__performance_test is True:
+ return self.request_process_performance(method, url, params, parse)
+ else:
+ return self.request_process_product(method, url, params, parse)
+
+ def request_process_product(self, method, url, params, parse):
+ request = self.create_request(method, url, params, parse)
+ if request:
+ return call_sync(request)
+
+ return None
+
+ def request_process_performance(self, method, url, params, parse):
+ request = self.create_request(method, url, params, parse)
+ if request:
+ return call_sync_perforence_test(request)
+
+ return None, 0, 0
+
+ """
+ for post batch operation, such as batch create orders[ /v1/order/batch-orders ]
+ """
+ def request_process_post_batch(self, method, url, params, parse):
+ if self.__performance_test is not None and self.__performance_test is True:
+ return self.request_process_post_batch_performance(method, url, params, parse)
+ else:
+ return self.request_process_post_batch_product(method, url, params, parse)
+
+ def request_process_post_batch_product(self, method, url, params, parse):
+ request = self.create_request_post_batch(method, url, params, parse)
+ if request:
+ return call_sync(request)
+
+ return None
+
+ def request_process_post_batch_performance(self, method, url, params, parse):
+ request = self.create_request_post_batch(method, url, params, parse)
+ if request:
+ return call_sync_perforence_test(request)
+
+ return None, 0, 0
+
diff --git a/huobi/connection/subscribe_client.py b/huobi/connection/subscribe_client.py
new file mode 100644
index 0000000..11a6d16
--- /dev/null
+++ b/huobi/connection/subscribe_client.py
@@ -0,0 +1,82 @@
+import logging
+
+from huobi.connection.impl.websocket_watchdog import WebSocketWatchDog
+from huobi.connection.impl.websocket_manage import WebsocketManage
+from huobi.connection.impl.websocket_request import WebsocketRequest
+from huobi.constant.system import WebSocketDefine, ApiVersion
+
+
+class SubscribeClient(object):
+ # static property
+ subscribe_watch_dog = WebSocketWatchDog()
+
+ def __init__(self, **kwargs):
+ """
+ Create the subscription client to subscribe the update from server.
+
+ :param kwargs: The option of subscription connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: Set the URI for subscription.
+ init_log: to init logger
+ """
+ self.__api_key = kwargs.get("api_key", None)
+ self.__secret_key = kwargs.get("secret_key", None)
+ self.__uri = kwargs.get("url", WebSocketDefine.Uri)
+ self.__init_log = kwargs.get("init_log", None)
+ if self.__init_log and self.__init_log:
+ logger = logging.getLogger("huobi-client")
+ logger.setLevel(level=logging.INFO)
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
+ logger.addHandler(handler)
+
+ self.__websocket_manage_list = list()
+
+ def __create_websocket_manage(self, request):
+ manager = WebsocketManage(self.__api_key, self.__secret_key, self.__uri, request)
+ self.__websocket_manage_list.append(manager)
+ manager.connect()
+ SubscribeClient.subscribe_watch_dog.on_connection_created(manager)
+
+ def create_request(self, subscription_handler, parse, callback, error_handler, is_trade, is_mbp_feed=False):
+ request = WebsocketRequest()
+ request.subscription_handler = subscription_handler
+ request.is_trading = is_trade
+ request.is_mbp_feed = is_mbp_feed
+ request.auto_close = False # subscribe need connection. websocket request need close request.
+ request.json_parser = parse
+ request.update_callback = callback
+ request.error_handler = error_handler
+ return request
+
+ def create_request_v1(self, subscription_handler, parse, callback, error_handler, is_trade=False):
+ request = self.create_request(subscription_handler=subscription_handler, parse=parse, callback=callback,
+ error_handler=error_handler, is_trade=is_trade)
+ request.api_version = ApiVersion.VERSION_V1
+ return request
+
+ def create_request_v2(self, subscription_handler, parse, callback, error_handler, is_trade=False):
+ request = self.create_request(subscription_handler=subscription_handler, parse=parse, callback=callback,
+ error_handler=error_handler, is_trade=is_trade)
+ request.api_version = ApiVersion.VERSION_V2
+ return request
+
+ def execute_subscribe_v1(self, subscription_handler, parse, callback, error_handler, is_trade=False):
+ request = self.create_request_v1(subscription_handler, parse, callback, error_handler, is_trade)
+ self.__create_websocket_manage(request)
+
+ def execute_subscribe_v2(self, subscription_handler, parse, callback, error_handler, is_trade=False):
+ request = self.create_request_v2(subscription_handler, parse, callback, error_handler, is_trade)
+ self.__create_websocket_manage(request)
+
+ def execute_subscribe_mbp(self, subscription_handler, parse, callback, error_handler, is_trade=False,
+ is_mbp_feed=True):
+ request = self.create_request(subscription_handler, parse, callback, error_handler, is_trade, is_mbp_feed)
+ self.__create_websocket_manage(request)
+
+ def unsubscribe_all(self):
+ for websocket_manage in self.__websocket_manage_list:
+ SubscribeClient.subscribe_watch_dog.on_connection_closed(websocket_manage)
+ websocket_manage.close()
+ self.__websocket_manage_list.clear()
diff --git a/huobi/connection/websocket_req_client.py b/huobi/connection/websocket_req_client.py
new file mode 100644
index 0000000..5e0c07a
--- /dev/null
+++ b/huobi/connection/websocket_req_client.py
@@ -0,0 +1,54 @@
+import logging
+
+from huobi.connection.impl.websocket_manage import WebsocketManage
+from huobi.connection.impl.websocket_request import WebsocketRequest
+from huobi.constant.system import WebSocketDefine
+
+
+class WebSocketReqClient(object):
+
+ def __init__(self, **kwargs):
+ """
+ Create the subscription client to subscribe the update from server.
+
+ :param kwargs: The option of subscription connection.
+ api_key: The public key applied from Huobi.
+ secret_key: The private key applied from Huobi.
+ url: Set the URI for subscription.
+ init_log: to init logger
+ """
+
+ self.__api_key = kwargs.get("api_key", None)
+ self.__secret_key = kwargs.get("secret_key", None)
+ self.__uri = kwargs.get("url", WebSocketDefine.Uri)
+ self.__init_log = kwargs.get("init_log", None)
+ if self.__init_log and self.__init_log:
+ logger = logging.getLogger("huobi-client")
+ logger.setLevel(level=logging.INFO)
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
+ logger.addHandler(handler)
+
+ def __create_websocket_manage(self, request):
+ manager = WebsocketManage(self.__api_key, self.__secret_key, self.__uri, request)
+ manager.connect()
+
+ def create_request(self, subscription_handler, parse, callback, error_handler, is_trade=False, is_mbp_feed=False):
+ request = WebsocketRequest()
+ request.subscription_handler = subscription_handler
+ request.is_trading = is_trade
+ request.is_mbp_feed = is_mbp_feed
+ request.auto_close = True # for websocket request, auto close the connection after request.
+ request.json_parser = parse
+ request.update_callback = callback
+ request.error_handler = error_handler
+ return request
+
+ def execute_subscribe_v1(self, subscription_handler, parse, callback, error_handler, is_trade=False):
+ request = self.create_request(subscription_handler, parse, callback, error_handler, is_trade)
+ self.__create_websocket_manage(request)
+
+ def execute_subscribe_mbp(self, subscription_handler, parse, callback, error_handler, is_trade=False,
+ is_mbp_feed=True):
+ request = self.create_request(subscription_handler, parse, callback, error_handler, is_trade, is_mbp_feed)
+ self.__create_websocket_manage(request)
diff --git a/huobi/constant/__init__.py b/huobi/constant/__init__.py
new file mode 100644
index 0000000..905e73b
--- /dev/null
+++ b/huobi/constant/__init__.py
@@ -0,0 +1,7 @@
+from huobi.constant.definition import *
+from huobi.constant.result import *
+from huobi.constant.system import *
+from huobi.constant.test import *
+
+
+
diff --git a/huobi/constant/definition.py b/huobi/constant/definition.py
new file mode 100644
index 0000000..3fdafaa
--- /dev/null
+++ b/huobi/constant/definition.py
@@ -0,0 +1,366 @@
+class CandlestickInterval:
+ MIN1 = "1min"
+ MIN5 = "5min"
+ MIN15 = "15min"
+ MIN30 = "30min"
+ MIN60 = "60min"
+ HOUR4 = "4hour"
+ DAY1 = "1day"
+ MON1 = "1mon"
+ WEEK1 = "1week"
+ YEAR1 = "1year"
+ INVALID = None
+
+
+class OrderSide:
+ BUY = "buy"
+ SELL = "sell"
+ INVALID = None
+
+
+class TradeDirection:
+ BUY = "buy"
+ SELL = "sell"
+ INVALID = None
+
+
+class OrderType:
+ SELL_LIMIT = "sell-limit"
+ BUY_LIMIT = "buy-limit"
+ BUY_MARKET = "buy-market"
+ SELL_MARKET = "sell-market"
+ BUY_IOC = "buy-ioc"
+ SELL_IOC = "sell-ioc"
+ BUY_LIMIT_MAKER = "buy-limit-maker"
+ SELL_LIMIT_MAKER = "sell-limit-maker"
+ BUY_STOP_LIMIT = "buy-stop-limit"
+ SELL_STOP_LIMIT = "sell-stop-limit"
+ BUY_LIMIT_FOK = "buy-limit-fok"
+ SELL_LIMIT_FOK = "sell-limit-fok"
+ BUY_STOP_LIMIT_FOK = "buy-stop-limit-fok"
+ SELL_STOP_LIMIT_FOK = "sell-stop-limit-fok"
+ INVALID = None
+
+
+class AlgoOrderType:
+ LIMIT = "limit"
+ MARKET = "market"
+
+
+class AlgoOrderStatus:
+ CANCELED = "canceled"
+ REJECTED = "rejected"
+ TRIGGERED = "triggered"
+
+
+class AccountType:
+ SPOT = "spot"
+ MARGIN = "margin"
+ OTC = "otc"
+ POINT = "point"
+ MINEPOLL = "minepool"
+ ETF = "etf"
+ AGENCY = "agency"
+ SUPER_MARGIN = "super-margin"
+ INVALID = None
+
+
+class AccountState:
+ WORKING = "working"
+ LOCK = "lock"
+ INVALID = None
+
+
+class AccountPointState:
+ WORKING = "working"
+ LOCK = "lock"
+ INVALID = None
+ FL_SYS = "fl-sys"
+ FL_MGT = "fl-mgt"
+ FL_END = "fl-end"
+ FL_NEGATIVE = "fl-negative"
+
+
+class AccountBalanceUpdateType:
+ TRADE = "trade"
+ FROZEN = "frozen"
+ LOAN = "loan"
+ INTEREST = "interest"
+ LOAN_AVAILABLE = "loan-available"
+ TRANSFER_OUT_AVAILABLE = "transfer-out-available"
+ INVALID = None
+
+
+class WithdrawState:
+ SUBMITTED = "submitted"
+ REEXAMINE = "reexamine"
+ CANCELED = "canceled"
+ PASS = "pass"
+ REJECT = "reject"
+ PRETRANSFER = "pre-transfer"
+ WALLETTRANSFER = "wallet-transfer"
+ WALEETREJECT = "wallet-reject"
+ CONFIRMED = "confirmed"
+ CONFIRMERROR = "confirm-error"
+ REPEALED = "repealed"
+ VERIFYING = "verifying"
+ FAILED = "failed"
+ INVALID = None
+
+
+class DepositWithdraw:
+ DEPOSIT = "deposit"
+ WITHDRAW = "withdraw"
+
+
+class DepositState:
+ CONFIRMING = "confirming"
+ SAFE = "safe"
+ CONFIRMED = "confirmed"
+ ORPHAN = "orphan"
+ INVALID = None
+
+
+class LoanOrderState:
+ CREATED = "created"
+ ACCRUAL = "accrual"
+ CLEARED = "cleared"
+ FAILED = "failed"
+ INVALID = None
+
+
+class OrderSource:
+ SYS = "sys"
+ WEB = "web"
+ API = "api"
+ APP = "app"
+ FL_SYS = "fl-sys"
+ FL_MGT = "fl-mgt"
+ SPOT_WEB = "spot-web"
+ SPOT_API = "spot-api"
+ SPOT_APP = "spot-app"
+ MARGIN_API = "margin-api"
+ MARGIN_WEB = "margin-web"
+ MARGIN_APP = "margin-app"
+ SUPER_MARGIN_API = "super-margin-api"
+ SUPER_MARGIN_WEB = "super-margin-web"
+ SUPER_MARGIN_APP = "super-margin-app"
+ SUPER_MARGIN_FL_SYS = "super-margin-fl-sys"
+ SUPER_MARGIN_FL_MGT = "super-margin-fl-mgt"
+ INVALID = None
+
+
+class OrderState:
+ CREATED = "created" # for stop loss order
+ PRE_SUBMITTED = "pre-submitted"
+ SUBMITTING = "submitting"
+ SUBMITTED = "submitted"
+ PARTIAL_FILLED = "partial-filled"
+ CANCELLING = "cancelling"
+ PARTIAL_CANCELED = "partial-canceled"
+ FILLED = "filled"
+ CANCELED = "canceled"
+ FAILED = "failed"
+ PLACE_TIMEOUT = "place_timeout"
+ INVALID = None
+
+
+class TimeInForceType:
+ IOC = "ioc"
+ FOK = "fok"
+ BOC = "boc"
+ GTC = "gtc"
+
+
+class TransferMasterType:
+ IN = "master-transfer-in"
+ OUT = "master-transfer-out"
+ POINT_IN = "master-point-transfer-in"
+ POINT_OUT = "master-point-transfer-out"
+ INVALID = None
+
+
+class EtfStatus:
+ NORMAL = "1"
+ REBALANCING_START = "2"
+ CREATION_AND_REDEMPTION_SUSPEND = "3"
+ CREATION_SUSPEND = "4"
+ REDEMPTION_SUSPEND = "5"
+ INVALID = None
+
+
+class EtfSwapType:
+ IN = "1"
+ OUT = "2"
+ INVALID = None
+
+
+class AccountChangeType:
+ NEWORDER = "order.place"
+ TRADE = "order.match"
+ REFUND = "order.refund"
+ CANCELORDER = "order.cancel"
+ FEE = "order.fee-refund"
+ TRANSFER = "margin.transfer"
+ LOAN = "margin.loan"
+ INTEREST = "margin.interest"
+ REPAY = "margin.repay"
+ OTHER = "other"
+ INVALID = None
+
+
+class BalanceMode:
+ AVAILABLE = "0"
+ TOTAL = "1"
+ INVALID = None
+
+
+class AccountBalanceMode:
+ BALANCE = "0"
+ TOTAL = "1"
+ INVALID = None
+
+
+class OperateMode:
+ PING = "ping"
+ PONG = "pong"
+ INVALID = None
+
+
+class QueryDirection:
+ PREV = "prev"
+ NEXT = "next"
+ INVALID = None
+
+
+class TransferFuturesPro:
+ TO_PRO = "futures-to-pro"
+ TO_FUTURES = "pro-to-futures"
+
+
+class MatchRole:
+ MAKER = "maker"
+ TAKER = "taker"
+
+
+class DepthStep:
+ STEP0 = "step0"
+ STEP1 = "step1"
+ STEP2 = "step2"
+ STEP3 = "step3"
+ STEP4 = "step4"
+ STEP5 = "step5"
+
+
+class DepthSize:
+ SIZE5 = 5
+ SIZE10 = 10
+ SIZE20 = 20
+
+
+class MbpLevel:
+ MBP5 = 5
+ MBP10 = 10
+ MBP20 = 20
+ MBP150 = 150
+
+
+class ChainDepositStatus:
+ ALLOWED = "allowed"
+ PROHIBITED = "prohibited"
+ INVALID = None
+
+
+class ChainWithdrawStatus:
+ ALLOWED = "allowed"
+ PROHIBITED = "prohibited"
+ INVALID = None
+
+
+class InstrumentStatus:
+ NORMAL = "normal"
+ DELISTED = "delisted"
+ INVALID = None
+
+
+class AccountChangeType:
+ ORDER_PLACE = "order-place"
+ ORDER_MATCH = "order-match"
+ ORDER_REFUND = "order-refund"
+ ORDER_CANCEL = "order-cancel"
+ ORDER_FEE_REFUND = "order-fee-refund"
+ MARGIN_TRANSFER = "margin-transfer"
+ MARGIN_LOAN = "margin-loan"
+ MARGIN_INTEREST = "margin-interest"
+ MARGIN_REPAY = "margin-repay"
+ OTHER = "other"
+ DEPOSIT = "deposit"
+ WITHDRAW = "withdraw"
+ INVALID = None
+
+
+class FeeDeductType:
+ DEDUCT_BY_HT = "ht"
+ DEDUCT_BY_POINT = "point"
+ INVALID = None
+
+
+class SubUidAction:
+ UNLOCK = "unlock"
+ LOCK = "lock"
+ INVALID = None
+
+
+class SubUidState:
+ NORMAL = "normal"
+ LOCK = "lock"
+ INVALID = None
+
+
+class OrderUpdateEventType:
+ CREATION = "creation"
+ TRADE = "trade"
+ CANCELLATION = "cancellation"
+ INVALID = None
+
+
+class AccountTransactType:
+ TRADE = "trade"
+ ETF = "etf"
+ TRANSACT_FEE = "transact-fee"
+ DEDUCTION = "deduction"
+ TRANSFER = "transfer"
+ CREDIT = "credit"
+ LIQUIDATION = "liquidation"
+ INTEREST = "interest"
+ DEPOSIT = "deposit"
+ WITHDRAW = "withdraw"
+ WITHDRAW_FEE = "withdraw-fee"
+ EXCHANGE = "exchange"
+ OTHER = "other-types"
+
+
+class SortDesc:
+ ASC = "asc"
+ DESC = "desc"
+
+
+class SubuserTradePrivilegeType:
+ MARGIN = "isolated-margin"
+ SUPER_MARGIN = "cross-margin"
+
+
+class SubUserTradeStatus:
+ ACTIVATED = "activated"
+ DEACTIVATED = "deactivated"
+
+
+class MarketStatus:
+ NORMAL = 1
+ HALTED = 2
+ CANCEL_ONLY = 3
+
+
+class HaltReason:
+ EMERGENCY_MAINTENANCE = 2
+ SCHEDULED_MAINTENANCE = 3
diff --git a/huobi/constant/result.py b/huobi/constant/result.py
new file mode 100644
index 0000000..0026777
--- /dev/null
+++ b/huobi/constant/result.py
@@ -0,0 +1,11 @@
+
+class OutputKey:
+ KeyData = "data"
+ KeyTick = "tick"
+ KeyChannelCh = "ch"
+ KeyChannelRep = "rep"
+
+
+
+
+
diff --git a/huobi/constant/system.py b/huobi/constant/system.py
new file mode 100644
index 0000000..f459404
--- /dev/null
+++ b/huobi/constant/system.py
@@ -0,0 +1,32 @@
+
+HUOBI_URL_PRO = "https://api.huobi.pro"
+HUOBI_URL_VN = "https://api.huobi.vn"
+HUOBI_URL_SO = "https://api.huobi.so"
+
+
+HUOBI_WEBSOCKET_URI_PRO = "wss://api.huobi.pro"
+HUOBI_WEBSOCKET_URI_VN = "wss://api.huobi.vn"
+HUOBI_WEBSOCKET_URI_SO = "wss://api.huobi.so"
+
+class WebSocketDefine:
+ Uri = HUOBI_WEBSOCKET_URI_PRO
+
+class RestApiDefine:
+ Url = HUOBI_URL_PRO
+
+class HttpMethod:
+ GET = "GET"
+ GET_SIGN = "GET_SIGN"
+ POST = "POST"
+ POST_SIGN = "POST_SIGN"
+
+
+class ApiVersion:
+ VERSION_V1 = "v1"
+ VERSION_V2 = "v2"
+
+def get_default_server_url(user_configed_url):
+ if user_configed_url and len(user_configed_url):
+ return user_configed_url
+ else:
+ return RestApiDefine.Url
diff --git a/huobi/constant/test.py b/huobi/constant/test.py
new file mode 100644
index 0000000..4dad710
--- /dev/null
+++ b/huobi/constant/test.py
@@ -0,0 +1,10 @@
+g_api_key="xxxxxx"
+g_secret_key="xxxxxx"
+
+
+
+
+g_sub_uid = 123456
+
+g_account_id = 123456
+
diff --git a/huobi/exception/__init__.py b/huobi/exception/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/exception/huobi_api_exception.py b/huobi/exception/huobi_api_exception.py
new file mode 100644
index 0000000..5f18e28
--- /dev/null
+++ b/huobi/exception/huobi_api_exception.py
@@ -0,0 +1,14 @@
+
+class HuobiApiException(Exception):
+
+ RUNTIME_ERROR = "RuntimeError"
+ INPUT_ERROR = "InputError"
+ KEY_MISSING = "KeyMissing"
+ SYS_ERROR = "SysError"
+ SUBSCRIPTION_ERROR = "SubscriptionError"
+ ENV_ERROR = "EnvironmentError"
+ EXEC_ERROR = "ExecuteError"
+
+ def __init__(self, error_code, error_message):
+ self.error_code = error_code
+ self.error_message = error_message
diff --git a/huobi/model/__init__.py b/huobi/model/__init__.py
new file mode 100644
index 0000000..fd40910
--- /dev/null
+++ b/huobi/model/__init__.py
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/huobi/model/account/__init__.py b/huobi/model/account/__init__.py
new file mode 100644
index 0000000..78d8613
--- /dev/null
+++ b/huobi/model/account/__init__.py
@@ -0,0 +1,14 @@
+from huobi.model.account.account import Account
+from huobi.model.account.account_balance import AccountBalance
+from huobi.model.account.account_balance_req import AccountBalanceReq
+from huobi.model.account.account_update import AccountUpdate
+from huobi.model.account.account_update_event import AccountUpdateEvent
+from huobi.model.account.balance import Balance
+from huobi.model.account.complete_subaccount import CompleteSubAccount
+from huobi.model.account.margin_balance_detail import MarginBalanceDetail
+from huobi.model.account.account_history import AccountHistory
+from huobi.model.account.sub_uid_management import SubUidManagement
+from huobi.model.account.account_ledger import AccountLedger
+from huobi.model.account.account_transfer_result import AccountTransferResult
+from huobi.model.account.account_point_result import AccountPointResult
+from huobi.model.account.account_point_transfer_result import AccountPointTransferResult
diff --git a/huobi/model/account/account.py b/huobi/model/account/account.py
new file mode 100644
index 0000000..d1e7535
--- /dev/null
+++ b/huobi/model/account/account.py
@@ -0,0 +1,27 @@
+from huobi.constant import *
+
+
+class Account:
+ """
+ The account information for spot account, margin account etc.
+
+ :member
+ id: The unique account id.
+ account_type: The type of this account, possible value: spot, margin, otc, point.
+ account_state: The account state, possible value: working, lock.
+ balances: The balance list of the specified currency. The content is Balance class
+
+ """
+
+ def __init__(self):
+ self.id = 0
+ self.type = AccountType.INVALID
+ self.state = AccountState.INVALID
+ self.subtype = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.type, format_data + "Account Type")
+ PrintBasic.print_basic(self.state, format_data + "Account State")
+ PrintBasic.print_basic(self.subtype, format_data + "Subtype")
diff --git a/huobi/model/account/account_asset_valuation.py b/huobi/model/account/account_asset_valuation.py
new file mode 100644
index 0000000..c0b78ee
--- /dev/null
+++ b/huobi/model/account/account_asset_valuation.py
@@ -0,0 +1,18 @@
+class AccountAssetValuationResult:
+ """
+ The account information for spot account, margin account etc.
+
+ :member
+ balance: balance valuation bases on given valuation currency.
+ timestamp: unix timestamp from server.
+
+ """
+
+ def __init__(self):
+ self.balance = ""
+ self.timestamp = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.balance, format_data + "balance")
+ PrintBasic.print_basic(self.timestamp, format_data + "timestamp")
diff --git a/huobi/model/account/account_balance.py b/huobi/model/account/account_balance.py
new file mode 100644
index 0000000..66cbc48
--- /dev/null
+++ b/huobi/model/account/account_balance.py
@@ -0,0 +1,58 @@
+from huobi.constant import *
+from huobi.model.account.balance import Balance
+from huobi.utils import default_parse, default_parse_list_dict
+
+
+class AccountBalance:
+ """
+ The account information for spot account, margin account etc.
+
+ :member
+ id: The unique account id.
+ account_type: The type of this account, possible value: spot, margin, otc, point.
+ account_state: The account state, possible value: working, lock.
+ list: The balance list of the specified currency. The content is Balance class
+
+ """
+
+ def __init__(self):
+ self.id = 0
+ self.type = AccountType.INVALID
+ self.state = AccountState.INVALID
+ self.subtype = ""
+ self.list = list()
+
+ @staticmethod
+ def json_parse(data_dict):
+ if data_dict and len(data_dict):
+ balance_list = data_dict.get("list")
+ data_dict.pop("list")
+ account_balance_obj = default_parse(data_dict, AccountBalance, Balance)
+ account_balance_obj.subtype = data_dict.get("subtype", data_dict.get("symbol"))
+ account_balance_obj.list = default_parse_list_dict(balance_list, Balance, [])
+ return account_balance_obj
+
+ return None
+
+ @staticmethod
+ def json_parse_list(data_list):
+ account_balance_list = []
+ if data_list and len(data_list):
+ for item in data_list:
+ item_obj = AccountBalance.json_parse(item)
+ if item_obj:
+ account_balance_list.append(item_obj)
+ return account_balance_list
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "Account ID")
+ PrintBasic.print_basic(self.type, format_data + "Account Type")
+ PrintBasic.print_basic(self.state, format_data + "Account State")
+ PrintBasic.print_basic(self.subtype, format_data + "Subtype")
+
+ print()
+ if len(self.list):
+ for row in self.list:
+ row.print_object(format_data+"\t")
+ print()
diff --git a/huobi/model/account/account_balance_req.py b/huobi/model/account/account_balance_req.py
new file mode 100644
index 0000000..9539db2
--- /dev/null
+++ b/huobi/model/account/account_balance_req.py
@@ -0,0 +1,30 @@
+
+class AccountBalanceReq:
+ """
+ The account change information received by subscription of account.
+
+ :member
+ ts: The UNIX formatted timestamp generated by server in UTC.
+ cid: client request ID
+ topic: request Channel or Topic
+ data: The list of account and balance
+
+ """
+
+ def __init__(self):
+ self.ts = 0
+ self.cid = ""
+ self.topic = ""
+ self.data = list()
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ts, format_data + "Timestamp")
+ PrintBasic.print_basic(self.cid, format_data + "Client Order ID")
+ PrintBasic.print_basic(self.topic, format_data + "Topic")
+ print()
+ if len(self.data):
+ for account_balance in self.data:
+ account_balance.print_object()
+ print()
\ No newline at end of file
diff --git a/huobi/model/account/account_history.py b/huobi/model/account/account_history.py
new file mode 100644
index 0000000..3719483
--- /dev/null
+++ b/huobi/model/account/account_history.py
@@ -0,0 +1,36 @@
+class AccountHistory:
+ """
+ The account information for spot account, margin account etc.
+
+ :member
+ account_id: Account Id.
+ currency: Currency name
+ transact_amt: Amount change (positive value if income, negative value if outcome)
+ transact-type: Amount change type
+ avail_balance: Available balance
+ acct_balance: Account balance
+ transact_time: Transaction time (database time)
+ record_id: Unique record ID in the database
+
+ """
+
+ def __init__(self):
+ self.account_id = 0
+ self.currency = ""
+ self.transact_amt = ""
+ self.transact_type = ""
+ self.avail_balance = ""
+ self.acct_balance = ""
+ self.transact_time = 0
+ self.record_id = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.account_id, format_data + "Account Id")
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.transact_amt, format_data + "Transact Amount")
+ PrintBasic.print_basic(self.transact_type, format_data + "Transact Type")
+ PrintBasic.print_basic(self.avail_balance, format_data + "Avail Balance")
+ PrintBasic.print_basic(self.acct_balance, format_data + "Account Balance")
+ PrintBasic.print_basic(self.transact_time, format_data + "Transact Time")
+ PrintBasic.print_basic(self.record_id, format_data + "Record Id")
diff --git a/huobi/model/account/account_ledger.py b/huobi/model/account/account_ledger.py
new file mode 100644
index 0000000..bf08d4a
--- /dev/null
+++ b/huobi/model/account/account_ledger.py
@@ -0,0 +1,38 @@
+class AccountLedger:
+ """
+ The account ledger information.
+
+ :member
+ accountId: Account ID.
+ currency: Cryptocurrency.
+ transactAmt: Transaction amount (income positive, expenditure negative).
+ transactType: Transaction type.
+ transferType: Transfer type (only valid for transactType=transfer).
+ transactId: Transaction ID.
+ transactTime: Transaction time.
+ transferer: Transferer’s account ID.
+ transferee: Transferee’s account ID.
+ """
+
+ def __init__(self):
+ self.accountId = 0
+ self.currency = ""
+ self.transactAmt = 0.0
+ self.transactType = ""
+ self.transferType = ""
+ self.transactId = 0
+ self.transactTime = 0
+ self.transferer = 0
+ self.transferee = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.accountId, format_data + "Account ID")
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.transactAmt, format_data + "Transaction Amount")
+ PrintBasic.print_basic(self.transactType, format_data + "Transaction Type")
+ PrintBasic.print_basic(self.transferType, format_data + "Transfer Type")
+ PrintBasic.print_basic(self.transactId, format_data + "Transaction ID")
+ PrintBasic.print_basic(self.transactTime, format_data + "Transaction Time")
+ PrintBasic.print_basic(self.transferer, format_data + "Transferer’s Account ID")
+ PrintBasic.print_basic(self.transferee, format_data + "Transferee’s Account ID")
\ No newline at end of file
diff --git a/huobi/model/account/account_point_group.py b/huobi/model/account/account_point_group.py
new file mode 100644
index 0000000..2a5223f
--- /dev/null
+++ b/huobi/model/account/account_point_group.py
@@ -0,0 +1,25 @@
+from huobi.constant import *
+
+
+class AccountPointGroup:
+ """
+ The account information for spot account, margin account etc.
+
+ :member
+ id: The unique account id.
+ account_type: The type of this account, possible value: spot, margin, otc, point.
+ account_state: The account state, possible value: working, lock.
+ list: The balance list of the specified currency. The content is Balance class
+
+ """
+
+ def __init__(self):
+ self.groupId = ""
+ self.expiryDate = ""
+ self.remainAmt = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.groupId, format_data + "Group Id")
+ PrintBasic.print_basic(self.expiryDate, format_data + "Expiration date")
+ PrintBasic.print_basic(self.remainAmt, format_data + "Remain Amount")
diff --git a/huobi/model/account/account_point_result.py b/huobi/model/account/account_point_result.py
new file mode 100644
index 0000000..4a28b1a
--- /dev/null
+++ b/huobi/model/account/account_point_result.py
@@ -0,0 +1,46 @@
+from huobi.constant import *
+from huobi.model.account.account_point_group import AccountPointGroup
+from huobi.utils import default_parse, default_parse_list_dict
+
+
+class AccountPointResult:
+ """
+ The account information for spot account, margin account etc.
+
+ :member
+ id: The unique account id.
+ account_type: The type of this account, possible value: spot, margin, otc, point.
+ account_state: The account state, possible value: working, lock.
+ list: The balance list of the specified currency. The content is Balance class
+
+ """
+
+ def __init__(self):
+ self.accountId = ""
+ self.accountStatus = AccountPointState.INVALID
+ self.groupIds = list()
+ self.acctBalance = ""
+
+ @staticmethod
+ def json_parse(data_dict):
+ if data_dict and len(data_dict):
+ group_ids = data_dict.get("groupIds")
+ data_dict.pop("groupIds")
+ account_point_obj = default_parse(data_dict, AccountPointResult, AccountPointGroup)
+ account_point_obj.subtype = data_dict.get("subtype", data_dict.get("symbol"))
+ account_point_obj.list = default_parse_list_dict(group_ids, AccountPointGroup, [])
+ return account_point_obj
+
+ return None
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.accountId, format_data + "Account ID")
+ PrintBasic.print_basic(self.accountStatus, format_data + "Account Status")
+ PrintBasic.print_basic(self.acctBalance, format_data + "Account Balance")
+
+ print()
+ if len(self.groupIds):
+ for row in self.groupIds:
+ row.print_object(format_data + "\t")
+ print()
diff --git a/huobi/model/account/account_point_transfer_result.py b/huobi/model/account/account_point_transfer_result.py
new file mode 100644
index 0000000..bc9c72f
--- /dev/null
+++ b/huobi/model/account/account_point_transfer_result.py
@@ -0,0 +1,20 @@
+class AccountPointTransferResult:
+ """
+ The account change information received by subscription of account.
+
+ :member
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ change_type: The event that asset change notification related.
+ account_change_list: The list of account change, the content is AccountChange class
+
+ """
+
+ def __init__(self):
+ self.transactId = ""
+ self.transactTime = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.transactId, format_data + "transactId")
+ PrintBasic.print_basic(self.transactTime, format_data + "transactTime")
+ self.data.print_object()
diff --git a/huobi/model/account/account_transfer_result.py b/huobi/model/account/account_transfer_result.py
new file mode 100644
index 0000000..9c5ae59
--- /dev/null
+++ b/huobi/model/account/account_transfer_result.py
@@ -0,0 +1,20 @@
+class AccountTransferResult:
+ """
+ The account information for spot account, margin account etc.
+
+ :member
+ id: The unique account id.
+ account_type: The type of this account, possible value: spot, margin, otc, point.
+ account_state: The account state, possible value: working, lock.
+ balances: The balance list of the specified currency. The content is Balance class
+
+ """
+
+ def __init__(self):
+ self.transact_id = 0
+ self.transact_time = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.transact_id, format_data + "TransactionId")
+ PrintBasic.print_basic(self.transact_time, format_data + "TransactionTime")
diff --git a/huobi/model/account/account_update.py b/huobi/model/account/account_update.py
new file mode 100644
index 0000000..ca3ad1d
--- /dev/null
+++ b/huobi/model/account/account_update.py
@@ -0,0 +1,35 @@
+from huobi.constant import *
+
+
+class AccountUpdate:
+ """
+ The account change information received by subscription of account.
+
+ :member
+ currency: The currency of the change.
+ accountId: The account id.
+ balance: Account balance (only exists when account balance changed)
+ available: Available balance (only exists when available balance changed)
+ changeType: Change type see AccountChangeType, valid value: order-place,order-match,order-refund,order-cancel,order-fee-refund,margin-transfer,margin-loan,margin-interest,margin-repay,other,
+ accountType: Account type see AccountBalanceUpdateType, valid value: trade, frozen, loan, interest
+ changeTime: Change time, unix time in millisecond
+ """
+
+ def __init__(self):
+ self.currency = ""
+ self.accountId = 0
+ self.balance = ""
+ self.available = ""
+ self.changeType = AccountChangeType.INVALID
+ self.accountType = AccountBalanceUpdateType.INVALID
+ self.changeTime = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.accountId, format_data + "Account ID")
+ PrintBasic.print_basic(self.balance, format_data + "Balance")
+ PrintBasic.print_basic(self.available, format_data + "Available")
+ PrintBasic.print_basic(self.changeType, format_data + "Account Change Type")
+ PrintBasic.print_basic(self.accountType, format_data + "Account Balance Change Type")
+ PrintBasic.print_basic(self.changeTime, format_data + "Account Timestamp")
diff --git a/huobi/model/account/account_update_event.py b/huobi/model/account/account_update_event.py
new file mode 100644
index 0000000..4400983
--- /dev/null
+++ b/huobi/model/account/account_update_event.py
@@ -0,0 +1,23 @@
+from huobi.constant import *
+from huobi.model.account import AccountUpdate
+
+
+class AccountUpdateEvent:
+ """
+ The account change information received by subscription of account.
+
+ :member
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ change_type: The event that asset change notification related.
+ account_change_list: The list of account change, the content is AccountChange class
+
+ """
+
+ def __init__(self):
+ self.ch = 0
+ self.data = AccountUpdate()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ch, format_data + "Topic")
+ self.data.print_object()
\ No newline at end of file
diff --git a/huobi/model/account/balance.py b/huobi/model/account/balance.py
new file mode 100644
index 0000000..01621e7
--- /dev/null
+++ b/huobi/model/account/balance.py
@@ -0,0 +1,25 @@
+from huobi.constant import *
+from huobi.utils import default_parse_list_dict
+
+
+class Balance:
+ """
+ The balance of specified account.
+
+ :member
+ currency: The currency of this balance.
+ balance_type: The balance type, trade or frozen.
+ balance: The balance in the main currency unit.
+
+ """
+
+ def __init__(self):
+ self.currency = ""
+ self.type = AccountBalanceUpdateType.INVALID
+ self.balance = 0.0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.type, format_data + "Balance Type")
+ PrintBasic.print_basic(self.balance, format_data + "Balance")
\ No newline at end of file
diff --git a/huobi/model/account/complete_subaccount.py b/huobi/model/account/complete_subaccount.py
new file mode 100644
index 0000000..a49a163
--- /dev/null
+++ b/huobi/model/account/complete_subaccount.py
@@ -0,0 +1,27 @@
+
+from huobi.constant import *
+
+
+class CompleteSubAccount:
+ """
+ Sub-account completed info
+
+ :member
+ id: The sub-id.
+ account_type: The sub account type.
+ balances: The balance list, the content is Balance class.
+ """
+
+ def __init__(self):
+ self.id = 0
+ self.account_type = AccountType.INVALID
+ self.balances = list()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.account_type, format_data + "Account Type")
+ if len(self.balances):
+ for row in self.balances:
+ row.print_object()
+ print()
\ No newline at end of file
diff --git a/huobi/model/account/margin_balance_detail.py b/huobi/model/account/margin_balance_detail.py
new file mode 100644
index 0000000..6e7da7a
--- /dev/null
+++ b/huobi/model/account/margin_balance_detail.py
@@ -0,0 +1,24 @@
+
+from huobi.constant import *
+
+
+class MarginBalanceDetail:
+ def __init__(self):
+ self.id = 0
+ self.symbol = 0
+ self.state = AccountState.INVALID
+ self.type = AccountType.INVALID
+ self.risk_rate = 0.0
+ self.fl_price = 0.0
+ self.fl_type = ""
+ self.sub_account_balance_list = list()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.type, format_data + "Account Type")
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.state, format_data + "Account State")
+ PrintBasic.print_basic(self.fl_price, format_data + "Burst Price")
+ PrintBasic.print_basic(self.fl_type, format_data + "Burst Type")
+ PrintBasic.print_basic(self.risk_rate, format_data + "Risk Rate")
\ No newline at end of file
diff --git a/huobi/model/account/sub_uid_management.py b/huobi/model/account/sub_uid_management.py
new file mode 100644
index 0000000..9d3266e
--- /dev/null
+++ b/huobi/model/account/sub_uid_management.py
@@ -0,0 +1,20 @@
+from huobi.constant import SubUidState
+
+
+class SubUidManagement:
+ """
+ The trade information with price and amount etc.
+
+ :member
+ subUid: sub user ID.
+ userState: sub user account state, states see SubUidState.
+ """
+
+ def __init__(self):
+ self.subUid = 0
+ self.userState = SubUidState.INVALID
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.subUid, format_data + "subUid")
+ PrintBasic.print_basic(self.userState, format_data + "userState")
diff --git a/huobi/model/algo/__init__.py b/huobi/model/algo/__init__.py
new file mode 100644
index 0000000..a7279a2
--- /dev/null
+++ b/huobi/model/algo/__init__.py
@@ -0,0 +1,3 @@
+from huobi.model.algo.cancel_order_result import CancelOrderResult
+from huobi.model.algo.order_list_item import OrderListItem
+from huobi.model.algo.order_history_item import OrderHistoryItem
diff --git a/huobi/model/algo/cancel_order_result.py b/huobi/model/algo/cancel_order_result.py
new file mode 100644
index 0000000..1ab3faa
--- /dev/null
+++ b/huobi/model/algo/cancel_order_result.py
@@ -0,0 +1,17 @@
+class CancelOrderResult:
+ """
+ The result of batch cancel operation.
+
+ :member
+ accepted: The clientOrderIds accepted.
+ rejected: The clientOrderIds rejected .
+
+ """
+
+ def __init__(self):
+ self.accepted = []
+ self.rejected = []
+
+ def print_object(self, format_data=""):
+ print("Success Order Counts", len(self.accepted), " accepted Order Ids : ", self.accepted)
+ print("Fail Order Counts", len(self.rejected), " Rejected Order Ids : ", self.rejected)
\ No newline at end of file
diff --git a/huobi/model/algo/order_history_item.py b/huobi/model/algo/order_history_item.py
new file mode 100644
index 0000000..f9b9020
--- /dev/null
+++ b/huobi/model/algo/order_history_item.py
@@ -0,0 +1,51 @@
+class OrderHistoryItem:
+ """
+ The result of batch cancel operation.
+
+ :member
+ orderOrigTime
+ lastActTime
+ symbol
+ source
+ orderSide
+ orderType
+ timeInForce
+ clientOrderId
+ accountId
+ orderPrice
+ orderSize
+ stopPrice
+ orderStatus
+
+ """
+
+ def __init__(self):
+ self.orderOrigTime = ""
+ self.lastActTime = ""
+ self.symbol = ""
+ self.source = ""
+ self.orderSide = ""
+ self.orderType = ""
+ self.timeInForce = ""
+ self.clientOrderId = ""
+ self.accountId = ""
+ self.orderPrice = ""
+ self.orderSize = ""
+ self.stopPrice = ""
+ self.orderStatus = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.orderOrigTime, format_data + "")
+ PrintBasic.print_basic(self.lastActTime, format_data + "")
+ PrintBasic.print_basic(self.symbol, format_data + "")
+ PrintBasic.print_basic(self.source, format_data + "")
+ PrintBasic.print_basic(self.orderSide, format_data + "")
+ PrintBasic.print_basic(self.orderType, format_data + "")
+ PrintBasic.print_basic(self.timeInForce, format_data + "")
+ PrintBasic.print_basic(self.clientOrderId, format_data + "")
+ PrintBasic.print_basic(self.accountId, format_data + "")
+ PrintBasic.print_basic(self.orderPrice, format_data + "")
+ PrintBasic.print_basic(self.orderSize, format_data + "")
+ PrintBasic.print_basic(self.stopPrice, format_data + "")
+ PrintBasic.print_basic(self.orderStatus, format_data + "")
diff --git a/huobi/model/algo/order_list_item.py b/huobi/model/algo/order_list_item.py
new file mode 100644
index 0000000..ee1e5b7
--- /dev/null
+++ b/huobi/model/algo/order_list_item.py
@@ -0,0 +1,73 @@
+class OrderListItem:
+ """
+ The result of batch cancel operation.
+
+ :member
+ event_type:
+ symbol:
+ order_id:
+ trade_price:
+ trade_volume:
+ order_side:
+ aggressor:
+ trade_id:
+ trade_time:
+ transact_fee:
+ fee_deduct:
+ fee_deduct_type:
+ fee_currency:
+ account_id:
+ source:
+ order_price:
+ order_size:
+ client_order_id:
+ order_create_time:
+ order_status:
+ """
+
+ def __init__(self):
+ self.eventType = ""
+ self.symbol = ""
+ self.orderId = ""
+ self.tradePrice = ""
+ self.tradeVolume = ""
+ self.orderSide = ""
+ self.aggressor = ""
+ self.tradeId = ""
+ self.tradeTime = ""
+ self.transactFee = ""
+ self.feeDeduct = ""
+ self.feeDeductType = ""
+ self.feeCurrency = ""
+ self.accountId = ""
+ self.source = ""
+ self.orderPrice = ""
+ self.orderSize = ""
+ self.clientOrderId = ""
+ self.orderCreateTime = ""
+ self.orderStatus = ""
+ self.trailingRate = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.eventType, format_data + "Event Type")
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.orderId, format_data + "OrderId")
+ PrintBasic.print_basic(self.tradePrice, format_data + "Trade Price")
+ PrintBasic.print_basic(self.tradeVolume, format_data + "Trade Volume")
+ PrintBasic.print_basic(self.orderSide, format_data + "Order Side")
+ PrintBasic.print_basic(self.aggressor, format_data + "Aggressor")
+ PrintBasic.print_basic(self.tradeId, format_data + "TradeId")
+ PrintBasic.print_basic(self.tradeTime, format_data + "Trade Time")
+ PrintBasic.print_basic(self.transactFee, format_data + "Transact Fee")
+ PrintBasic.print_basic(self.feeDeduct, format_data + "Fee Deduct")
+ PrintBasic.print_basic(self.feeDeductType, format_data + "Fee Deduct Type")
+ PrintBasic.print_basic(self.feeCurrency, format_data + "Fee Currency")
+ PrintBasic.print_basic(self.accountId, format_data + "Account Id")
+ PrintBasic.print_basic(self.source, format_data + "Source")
+ PrintBasic.print_basic(self.orderPrice, format_data + "Order Price")
+ PrintBasic.print_basic(self.orderSize, format_data + "Order Size")
+ PrintBasic.print_basic(self.clientOrderId, format_data + "Client Order Id")
+ PrintBasic.print_basic(self.orderCreateTime, format_data + "Order Create Time")
+ PrintBasic.print_basic(self.orderStatus, format_data + "Order Status")
+ PrintBasic.print_basic(self.trailingRate, format_data + "Trailing Rate (Trailing Order Only)")
diff --git a/huobi/model/etf/__init__.py b/huobi/model/etf/__init__.py
new file mode 100644
index 0000000..2ee6750
--- /dev/null
+++ b/huobi/model/etf/__init__.py
@@ -0,0 +1,4 @@
+from huobi.model.etf.etf_swap_config import EtfSwapConfig
+from huobi.model.etf.etf_swap_list import EtfSwapList
+from huobi.model.etf.etf_swap_in_out import EtfSwapInOut
+from huobi.model.etf.unitprice import UnitPrice
\ No newline at end of file
diff --git a/huobi/model/etf/etf_swap_config.py b/huobi/model/etf/etf_swap_config.py
new file mode 100644
index 0000000..aa8ea8e
--- /dev/null
+++ b/huobi/model/etf/etf_swap_config.py
@@ -0,0 +1,48 @@
+from huobi.constant import *
+
+
+class EtfSwapConfig:
+ """
+ The basic information of ETF creation and redemption, as well as ETF constituents, including max
+ amount of creation, min amount of creation, max amount of redemption, min amount of redemption,
+ creation fee rate, redemption fee rate, eft create/redeem status.
+
+ :member
+ purchase_max_amount: The max creation amounts per request.
+ purchase_min_amount: The minimum creation amounts per request.
+ redemption_max_amount: The max redemption amounts per request.
+ redemption_min_amount: The minimum redemption amounts per request.
+ purchase_fee_rate: The creation fee rate.
+ redemption_fee_rate: The redemption fee rate.
+ status: The status of the ETF.
+ unit_price_list: ETF constitution in format of amount and currency.
+
+ """
+ def __init__(self):
+ self.etf_name = ""
+ self.etf_status = EtfStatus.INVALID
+ self.purchase_fee_rate = 0.0
+ self.purchase_max_amount = 0
+ self.purchase_min_amount = 0
+ self.redemption_fee_rate = 0.0
+ self.redemption_max_amount = 0
+ self.redemption_min_amount = 0
+ self.unit_price = list()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.etf_name, format_data + "ETF Name")
+ PrintBasic.print_basic(self.etf_status, format_data + "ETF Status")
+
+ PrintBasic.print_basic(self.purchase_fee_rate, format_data + "Purchase Fee Rate")
+ PrintBasic.print_basic(self.purchase_max_amount, format_data + "Purchase Max Amount")
+ PrintBasic.print_basic(self.purchase_min_amount, format_data + "Purchase Min Amount")
+
+ PrintBasic.print_basic(self.redemption_fee_rate, format_data + "Redemption Fee Rate")
+ PrintBasic.print_basic(self.redemption_max_amount, format_data + "Redemption Max Amount")
+ PrintBasic.print_basic(self.redemption_min_amount, format_data + "Redemption Min Amount")
+ print()
+ if len(self.unit_price):
+ for row in self.unit_price:
+ row.print_object(format_data)
+ print()
diff --git a/huobi/model/etf/etf_swap_in_out.py b/huobi/model/etf/etf_swap_in_out.py
new file mode 100644
index 0000000..0641c19
--- /dev/null
+++ b/huobi/model/etf/etf_swap_in_out.py
@@ -0,0 +1,19 @@
+
+
+class EtfSwapInOut:
+ """
+ :member
+ """
+
+ def __init__(self):
+ self.code = 0
+ self.data = None
+ self.message = ""
+ self.success = False
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.code, format_data + "Return Code")
+ PrintBasic.print_basic_bool(self.data, format_data + "Data")
+ PrintBasic.print_basic(self.message, format_data + "Message")
+ PrintBasic.print_basic_bool(self.success, format_data + "Success")
diff --git a/huobi/model/etf/etf_swap_list.py b/huobi/model/etf/etf_swap_list.py
new file mode 100644
index 0000000..be879ec
--- /dev/null
+++ b/huobi/model/etf/etf_swap_list.py
@@ -0,0 +1,88 @@
+from huobi.constant import *
+from huobi.model.etf.unitprice import UnitPrice
+from huobi.utils import default_parse_list_dict
+
+
+class EtfSwapList:
+ """
+ The past creation and redemption.
+
+ :member
+ id: the operation Id.
+ gmt_created: The UNIX formatted timestamp in UTC of the operation.
+ currency: The ETF name.
+ amount: Creation or redemption amount.
+ type: The swap type. Creation or redemption.
+ status: The operation result
+ rate: The fee rate.
+ fee: The actual fee amount
+
+ point_card_amount: Discount from point card.
+ used_currency_list: For creation this is the list and amount of underlying assets used for ETF creation.
+ For redemption this is the amount of ETF used for redemption. The content is UnitPrice class.
+ obtain_currency_list: For creation this is the amount for ETF created.
+ For redemption this is the list and amount of underlying assets obtained. The content is UnitPrice class
+ """
+
+ def __init__(self):
+ self.id = 0
+ self.gmt_created = 0
+ self.currency = ""
+ self.amount = 0.0
+ self.type = EtfSwapType.INVALID
+ self.status = 0
+ self.rate = 0.0
+ self.fee = 0.0
+ self.point_card_amount = 0.0
+ self.used_currency_list = list()
+ self.obtain_currency_list = list()
+
+ @staticmethod
+ def json_parse(dict_data):
+ if dict_data and len(dict_data):
+ detail = dict_data.get("detail", {})
+ dict_data.pop("detail")
+ etf_swap_obj = default_parse_list_dict(dict_data, EtfSwapList)
+ if detail and len(detail):
+ etf_swap_obj.rate = detail.get("rate", 0)
+ etf_swap_obj.fee = detail.get("fee", 0)
+ etf_swap_obj.point_card_amount = detail.get("point_card_amount", 0)
+ etf_swap_obj.used_currency_list = default_parse_list_dict(detail.get("used_currency_list"), UnitPrice, [])
+ etf_swap_obj.obtain_currency_list = default_parse_list_dict(detail.get("obtain_currency_list"), UnitPrice, [])
+ return etf_swap_obj
+
+ return None
+
+ @staticmethod
+ def json_parse_list(dict_data):
+ ret_list = list()
+ for item in dict_data:
+ item_obj = EtfSwapList.json_parse(item)
+ if item_obj is not None:
+ ret_list.append(item_obj)
+
+ return ret_list
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "Operater Id")
+ PrintBasic.print_basic(self.gmt_created, format_data + "GMT Create Time")
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.type, format_data + "Type")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.rate, format_data + "Rate")
+ PrintBasic.print_basic(self.fee, format_data + "Fee")
+ PrintBasic.print_basic(self.status, format_data + "Status")
+ PrintBasic.print_basic(self.point_card_amount, format_data + "Point Card Amount")
+
+ if len(self.used_currency_list):
+ PrintBasic.print_basic("used_currency_list as below:")
+ for row in self.used_currency_list:
+ row.print_object(format_data + "\t")
+
+ if len(self.obtain_currency_list):
+ PrintBasic.print_basic("obtain_currency_list as below:")
+ for row in self.obtain_currency_list:
+ row.print_object(format_data + "\t")
+
diff --git a/huobi/model/etf/unitprice.py b/huobi/model/etf/unitprice.py
new file mode 100644
index 0000000..b9c3340
--- /dev/null
+++ b/huobi/model/etf/unitprice.py
@@ -0,0 +1,10 @@
+class UnitPrice:
+
+ def __init__(self):
+ self.currency = ""
+ self.amount = 0.0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
\ No newline at end of file
diff --git a/huobi/model/generic/__init__.py b/huobi/model/generic/__init__.py
new file mode 100644
index 0000000..08d45b4
--- /dev/null
+++ b/huobi/model/generic/__init__.py
@@ -0,0 +1,5 @@
+from huobi.model.generic.symbol import Symbol
+from huobi.model.generic.exchange_info import ExchangeInfo
+from huobi.model.generic.chain import Chain
+from huobi.model.generic.reference_currency import ReferenceCurrency
+from huobi.model.generic.market_status import MarketStatus
diff --git a/huobi/model/generic/chain.py b/huobi/model/generic/chain.py
new file mode 100644
index 0000000..1ae896d
--- /dev/null
+++ b/huobi/model/generic/chain.py
@@ -0,0 +1,69 @@
+from huobi.constant import *
+
+class Chain:
+ """
+ The Huobi Chain.
+
+ :member
+ chain: Chain name
+ numOfConfirmations: Number of confirmations required for deposit success (trading & withdrawal allowed once reached)
+ numOfFastConfirmations: Number of confirmations required for quick success (trading allowed but withdrawal disallowed once reached)
+ minDepositAmt: Minimal deposit amount in each request
+ depositStatus: Deposit status allowed,prohibited
+ minWithdrawAmt: Minimal withdraw amount in each request.
+ maxWithdrawAmt : Maximum withdraw amount in each request
+ withdrawQuotaPerDay : Maximum withdraw amount in a day
+ withdrawQuotaPerYear : Maximum withdraw amount in a year
+ withdrawQuotaTotal : Maximum withdraw amount in total
+ withdrawPrecision : Withdraw amount precision
+ withdrawFeeType : Type of withdraw fee (only one type can be applied to each currency)
+
+ transactFeeWithdraw : Withdraw fee in each request (only applicable to withdrawFeeType = fixed)
+ minTransactFeeWithdraw : Minimal withdraw fee in each request (only applicable to withdrawFeeType = circulated)
+ maxTransactFeeWithdraw : Maximum withdraw fee in each request (only applicable to withdrawFeeType = circulated or ratio)
+ transactFeeRateWithdraw : Withdraw fee in each request (only applicable to withdrawFeeType = ratio)
+ withdrawStatus : Withdraw status
+ """
+
+ def __init__(self):
+ self.chain = ""
+ self.baseChain = ""
+ self.baseChainProtocol = ""
+ self.numOfConfirmations = 0
+ self.numOfFastConfirmations = 0
+ self.depositStatus = ChainDepositStatus.INVALID
+ self.minDepositAmt = 0
+ self.withdrawStatus = ChainWithdrawStatus.INVALID
+ self.minWithdrawAmt = 0
+ self.withdrawPrecision = 0
+ self.maxWithdrawAmt = 0.0
+ self.withdrawQuotaPerDay = 0.0
+ self.withdrawQuotaPerYear = 0.0
+ self.withdrawQuotaTotal = 0.0
+ self.withdrawFeeType = ""
+ self.transactFeeWithdraw = 0.0
+ self.minTransactFeeWithdraw = 0.0
+ self.maxTransactFeeWithdraw = 0.0
+ self.transactFeeRateWithdraw = 0.0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.chain, format_data + "Chain")
+ PrintBasic.print_basic(self.baseChain, format_data + "Base Chain")
+ PrintBasic.print_basic(self.baseChainProtocol, format_data + "Base Chain Protocol")
+ PrintBasic.print_basic(self.numOfConfirmations, format_data + "numOfConfirmations")
+ PrintBasic.print_basic(self.numOfFastConfirmations, format_data + "numOfFastConfirmations")
+ PrintBasic.print_basic(self.depositStatus, format_data + "depositStatus")
+ PrintBasic.print_basic(self.minDepositAmt, format_data + "minDepositAmount")
+ PrintBasic.print_basic(self.withdrawStatus, format_data + "withdrawStatus")
+ PrintBasic.print_basic(self.minWithdrawAmt, format_data + "minWithdrawAmount")
+ PrintBasic.print_basic(self.withdrawPrecision, format_data + "withdrawPrecision")
+ PrintBasic.print_basic(self.maxWithdrawAmt, format_data + "maxWithdrawAmount")
+ PrintBasic.print_basic(self.withdrawQuotaPerDay, format_data + "withdrawQuotaPerDay")
+ PrintBasic.print_basic(self.withdrawQuotaPerYear, format_data + "withdrawQuotaPerYear")
+ PrintBasic.print_basic(self.withdrawQuotaTotal, format_data + "withdrawQuotaTotal")
+ PrintBasic.print_basic(self.withdrawFeeType, format_data + "withdrawFeeType")
+ PrintBasic.print_basic(self.transactFeeWithdraw, format_data + "transactFeeWithdraw")
+ PrintBasic.print_basic(self.minTransactFeeWithdraw, format_data + "minTransactFeeWithdraw")
+ PrintBasic.print_basic(self.maxTransactFeeWithdraw, format_data + "maxTransactFeeWithdraw")
+ PrintBasic.print_basic(self.transactFeeRateWithdraw, format_data + "transactFeeRateWithdraw")
diff --git a/huobi/model/generic/exchange_info.py b/huobi/model/generic/exchange_info.py
new file mode 100644
index 0000000..d0e6871
--- /dev/null
+++ b/huobi/model/generic/exchange_info.py
@@ -0,0 +1,12 @@
+class ExchangeInfo:
+ """
+ The Huobi supported the symbols and currencies.
+
+ :member
+ symbol_list: The symbol list. The content is Symbol class.
+ currencies: The currency list. The content is string value.
+ """
+
+ def __init__(self):
+ self.symbol_list = list()
+ self.currencies = list()
diff --git a/huobi/model/generic/market_status.py b/huobi/model/generic/market_status.py
new file mode 100644
index 0000000..4a5ac5c
--- /dev/null
+++ b/huobi/model/generic/market_status.py
@@ -0,0 +1,20 @@
+from huobi.constant import *
+
+
+class MarketStatus:
+ """
+ The Huobi market status info.
+
+ :member
+ marketStatus: .
+ haltStartTime: .
+ haltEndTime: .
+ haltReason:
+ affectedSymbols:
+ """
+
+ def __init__(self):
+ self.marketStatus = MarketStatus.NORMAL
+ self.haltStartTime = -1
+ self.haltEndTime = -1
+ self.affectedSymbols = ""
diff --git a/huobi/model/generic/reference_currency.py b/huobi/model/generic/reference_currency.py
new file mode 100644
index 0000000..9e52751
--- /dev/null
+++ b/huobi/model/generic/reference_currency.py
@@ -0,0 +1,26 @@
+from huobi.constant import *
+
+class ReferenceCurrency:
+ """
+ The Huobi supported static reference information for each currency.
+
+ :member
+ currency: currency
+ instStatus: Instrument status
+ chains: chain list
+ """
+
+ def __init__(self):
+ self.currency = ""
+ self.instStatus = InstrumentStatus.INVALID
+ self.chains = []
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.instStatus, format_data + "Instrument Status")
+ if self.chains and len(self.chains):
+ for chain_obj in self.chains:
+ chain_obj.print_object("\t")
+ print()
diff --git a/huobi/model/generic/symbol.py b/huobi/model/generic/symbol.py
new file mode 100644
index 0000000..e498c2a
--- /dev/null
+++ b/huobi/model/generic/symbol.py
@@ -0,0 +1,66 @@
+class Symbol:
+ """
+ The Huobi supported symbols.
+
+ :member
+ base_currency: The base currency in a trading symbol.
+ quote_currency: The quote currency in a trading symbol.
+ price_precision: The quote currency precision when quote price (decimal places).
+ amount_precision: The base currency precision when quote amount (decimal places).
+ symbol_partition: The trading section, possible values: [main,innovation,bifurcation].
+ symbol: The symbol, like "btcusdt".
+ state : trade status, maybe one in [online,offline,suspend]
+ value_precision : value precision
+ min_order_amt : minimum volume limit only used in limit-order and sell-market order
+ max_order_amt : Maximum volume
+ min_order_value : Minimum order amount
+ leverage_ratio : Leverage ratio for symbol
+ limit_order_min_order_amt: Minimum order amount of limit order in base currency (NEW)
+ limit_order_max_order_amt: Max order amount of limit order in base currency (NEW)
+ sell_market_min_order_amt: Minimum order amount of sell-market order in base currency (NEW)
+ sell_market_max_order_amt: Max order amount of sell-market order in base currency (NEW)
+ buy_market_max_order_amt: Max order value of buy-market order in quote currency (NEW)
+ max_order_value: Max order value of limit order and buy-market order in usdt (NEW)
+
+ """
+
+ def __init__(self):
+ self.base_currency = ""
+ self.quote_currency = ""
+ self.price_precision = 0
+ self.amount_precision = 0
+ self.symbol_partition = ""
+ self.symbol = ""
+ self.state = ""
+ self.value_precision = 0
+ self.min_order_amt = ""
+ self.max_order_amt = ""
+ self.min_order_value = ""
+ self.leverage_ratio = 0
+ self.limit_order_min_order_amt = 0
+ self.limit_order_max_order_amt = 0
+ self.sell_market_min_order_amt = 0
+ self.sell_market_max_order_amt = 0
+ self.buy_market_max_order_value = 0
+ self.max_order_value = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.base_currency, format_data + "Base Currency")
+ PrintBasic.print_basic(self.quote_currency, format_data + "Quote Currency")
+ PrintBasic.print_basic(self.price_precision, format_data + "Price Precision")
+ PrintBasic.print_basic(self.amount_precision, format_data + "Amount Precision")
+ PrintBasic.print_basic(self.symbol_partition, format_data + "Symbol Partition")
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.state, format_data + "State")
+ PrintBasic.print_basic(self.value_precision, format_data + "Value Precision")
+ PrintBasic.print_basic(self.min_order_amt, format_data + "Min Order Amount")
+ PrintBasic.print_basic(self.max_order_amt, format_data + "Max Order Amount")
+ PrintBasic.print_basic(self.min_order_value, format_data + "Min Order Value")
+ PrintBasic.print_basic(self.leverage_ratio, format_data + "Leverage Ratio")
+ PrintBasic.print_basic(self.limit_order_min_order_amt, format_data + "Minimum order amount (Limit Order)")
+ PrintBasic.print_basic(self.limit_order_max_order_amt, format_data + "Max order amount (Limit Order)")
+ PrintBasic.print_basic(self.sell_market_min_order_amt, format_data + "Min order amount (Sell Market Order)")
+ PrintBasic.print_basic(self.sell_market_max_order_amt, format_data + "Max order amount (Sell Market Order)")
+ PrintBasic.print_basic(self.buy_market_max_order_value, format_data + "Max order value (Buy Market Order)")
+ PrintBasic.print_basic(self.max_order_value, format_data + "Max order value (In USDT)")
diff --git a/huobi/model/margin/__init__.py b/huobi/model/margin/__init__.py
new file mode 100644
index 0000000..9e38399
--- /dev/null
+++ b/huobi/model/margin/__init__.py
@@ -0,0 +1,8 @@
+from huobi.model.margin.loan_order import LoanOrder
+from huobi.model.margin.margin_account_balance import MarginAccountBalance
+from huobi.model.margin.loan_ino import LoanInfo
+from huobi.model.margin.margin_loan_ino import MarginLoanInfo
+from huobi.model.margin.cross_margin_loan_ino import CrossMarginLoanInfo
+from huobi.model.margin.cross_margin_account_balance import CrossMarginAccountBalance
+
+
diff --git a/huobi/model/margin/cross_margin_account_balance.py b/huobi/model/margin/cross_margin_account_balance.py
new file mode 100644
index 0000000..d62a89d
--- /dev/null
+++ b/huobi/model/margin/cross_margin_account_balance.py
@@ -0,0 +1,49 @@
+from huobi.constant import *
+from huobi.model.account import Balance
+from huobi.utils import *
+
+
+class CrossMarginAccountBalance:
+
+ """
+ The account information for spot account, margin account etc.
+
+ :member
+ id: The unique account id.
+ type: The type of this account, possible value: spot, margin, otc, point.
+ state: The account state, possible value: working, lock.
+ list: The balance list of the specified currency. The content is Balance class
+ """
+
+
+ def __init__(self):
+ self.id = 0
+ self.type = AccountType.INVALID
+ self.state = AccountState.INVALID
+ self.risk_rate = 0
+ self.acct_balance_sum = 0.0
+ self.debt_balance_sum = 0.0
+ self.list = list()
+
+ @staticmethod
+ def json_parse(data_json):
+ balance_list_json = data_json.get("list", [])
+ data_json.pop("list")
+
+ account_balance = default_parse_list_dict(data_json, CrossMarginAccountBalance)
+ account_balance.list = default_parse_list_dict(balance_list_json, Balance, [])
+
+ return account_balance
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "Account ID")
+ PrintBasic.print_basic(self.type, format_data + "Account Type")
+ PrintBasic.print_basic(self.state, format_data + "Account State")
+ PrintBasic.print_basic(self.risk_rate, format_data + "Risk Rate")
+ PrintBasic.print_basic(self.acct_balance_sum, format_data + "Total Balance")
+ PrintBasic.print_basic(self.debt_balance_sum, format_data + "Debt Balance")
+ if self.list and len(self.list):
+ for balance in self.list:
+ balance.print_object("\t")
+ print()
diff --git a/huobi/model/margin/cross_margin_loan_ino.py b/huobi/model/margin/cross_margin_loan_ino.py
new file mode 100644
index 0000000..e9b6986
--- /dev/null
+++ b/huobi/model/margin/cross_margin_loan_ino.py
@@ -0,0 +1,9 @@
+
+from huobi.model.margin.loan_ino import LoanInfo
+
+class CrossMarginLoanInfo(LoanInfo):
+ def __init__(self):
+ LoanInfo.__init__(self)
+
+ def print_object(self, format_data=""):
+ LoanInfo.print_object(self)
diff --git a/huobi/model/margin/general_repay_loan_record.py b/huobi/model/margin/general_repay_loan_record.py
new file mode 100644
index 0000000..d0e0760
--- /dev/null
+++ b/huobi/model/margin/general_repay_loan_record.py
@@ -0,0 +1,59 @@
+from huobi.constant import *
+
+
+class GeneralRepayLoanRecord:
+ """
+ The general repay loan record information.
+
+ :member
+ repayId: repayment transaction ID.
+ repayTime: repayment transaction time (unix time in millisecond).
+ accountId: repayment account ID.
+ currency: repayment currency, like "usdt".
+ repaidAmount: repaid amount.
+ transactIds: ID list of original loan transactions (arranged by order of repayment time).
+ nextId: search the start ID in the next page (return only when there is data in the next page).
+ """
+
+ def __init__(self):
+ self.repayId = None
+ self.repayTime = None
+ self.accountId = None
+ self.currency = None
+ self.repaidAmount = None
+ self.transactIds = Transact()
+ self.nextId = None
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.repayId, format_data + "repayId")
+ PrintBasic.print_basic(self.repayTime, format_data + "repayTime")
+ PrintBasic.print_basic(self.accountId, format_data + "accountId")
+ PrintBasic.print_basic(self.currency, format_data + "currency")
+ PrintBasic.print_basic(self.repaidAmount, format_data + "repaidAmount")
+ PrintBasic.print_basic(self.transactIds, format_data + "transactIds")
+ PrintBasic.print_basic(self.nextId, format_data + "nextId")
+
+ print()
+
+
+class Transact:
+
+ """
+ The general repay loan record information.
+
+ :member
+ transactId: original loan transaction ID.
+ repaidPrincipal: principal repaid.
+ repaidInterest: interest repaid.
+ paidHt: HT paid.
+ paidPoint: point paid.
+ """
+
+ def __init__(self):
+ self.transactId = None
+ self.repaidPrincipal = None
+ self.repaidInterest = None
+ self.paidHt = None
+ self.paidPoint = None
+
diff --git a/huobi/model/margin/general_repay_loan_result.py b/huobi/model/margin/general_repay_loan_result.py
new file mode 100644
index 0000000..1b65954
--- /dev/null
+++ b/huobi/model/margin/general_repay_loan_result.py
@@ -0,0 +1,31 @@
+from huobi.constant import *
+
+
+class GeneralRepayLoanResult:
+ """
+ The margin order information.
+
+ :member
+ id: Inner id.
+ type: The account type.
+ state: The account state.
+ symbol: The symbol, like "btcusdt".
+ fl_price: The trigger price.
+ fl_type: The trigger type.
+ risk_rate: The risk rate.
+ list:Balance Object list
+ """
+
+ def __init__(self):
+ self.repayId = 0
+ self.repayTime = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.repayId, format_data + "repayId")
+ PrintBasic.print_basic(self.repayTime, format_data + "repayTime")
+
+ print()
+
+
+
diff --git a/huobi/model/margin/loan_ino.py b/huobi/model/margin/loan_ino.py
new file mode 100644
index 0000000..27bdba9
--- /dev/null
+++ b/huobi/model/margin/loan_ino.py
@@ -0,0 +1,30 @@
+
+class LoanInfo:
+ """
+ The margin rate define.
+
+ :member
+ currency: The currency name.
+ interest_rate: all interest rate
+ min_loan_amt: min loan amount.
+ max_loan_amt: max loan amount.
+ loanable_amt: loanable amount.
+ actual_rate: rate after deduction.
+ """
+
+ def __init__(self):
+ self.currency = ""
+ self.interest_rate = ""
+ self.min_loan_amt = ""
+ self.max_loan_amt = ""
+ self.loanable_amt = ""
+ self.actual_rate = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.interest_rate, format_data + "Interest Rate")
+ PrintBasic.print_basic(self.min_loan_amt, format_data + "Min Loan Amount")
+ PrintBasic.print_basic(self.max_loan_amt, format_data + "Max Loan Amount")
+ PrintBasic.print_basic(self.loanable_amt, format_data + "Loanable Amount")
+ PrintBasic.print_basic(self.actual_rate, format_data + "Actual Rate")
diff --git a/huobi/model/margin/loan_order.py b/huobi/model/margin/loan_order.py
new file mode 100644
index 0000000..8d92fe2
--- /dev/null
+++ b/huobi/model/margin/loan_order.py
@@ -0,0 +1,62 @@
+from huobi.constant import *
+
+
+class LoanOrder:
+ """
+ The margin order information.
+
+ :member
+ id: The order id.
+ user_id: The user id.
+ account_type: The account type which created the loan order.
+ currency: The currency name.
+ loan_amount: The amount of the origin loan.
+ loan_balance: The amount of the loan left.
+ interest_rate: The loan interest rate.
+ interest_amount: The accumulated loan interest.
+ interest_balance: The amount of loan interest left.
+ state: The loan stats, possible values: created, accrual, cleared, invalid.
+ created_at: The UNIX formatted timestamp in UTC when the order was created.
+ accrued_at: The UNIX formatted timestamp in UTC when the last accrue happened.
+ """
+
+ def __init__(self):
+ self.currency = ""
+ self.deduct_rate = 0
+ self.paid_point = 0.0
+ self.deduct_currency = ""
+ self.user_id = 0
+ self.created_at = 0
+ self.account_id = 0
+ self.paid_coin = 0.0
+ self.loan_amount = 0.0
+ self.interest_amount = 0.0
+ self.deduct_amount = 0.0
+ self.loan_balance = 0.0
+ self.interest_balance = 0.0
+ self.updated_at = 0
+ self.accrued_at = 0
+ self.interest_rate = 0.0
+ self.id = 0
+ self.state = LoanOrderState.INVALID
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.deduct_rate, format_data + "Deduct Rate")
+ PrintBasic.print_basic(self.paid_point, format_data + "Paid Point")
+ PrintBasic.print_basic(self.deduct_currency, format_data + "Deduct Currency")
+ PrintBasic.print_basic(self.user_id, format_data + "User Id")
+ PrintBasic.print_basic(self.created_at, format_data + "Create Time")
+ PrintBasic.print_basic(self.account_id, format_data + "Account Id")
+ PrintBasic.print_basic(self.paid_coin, format_data + "Paid Coin")
+ PrintBasic.print_basic(self.loan_amount, format_data + "Load Amount")
+ PrintBasic.print_basic(self.interest_amount, format_data + "Interest Amount")
+ PrintBasic.print_basic(self.deduct_amount, format_data + "Deduct Amount")
+ PrintBasic.print_basic(self.loan_balance, format_data + "Loan Balance")
+ PrintBasic.print_basic(self.interest_balance, format_data + "Interest Balance")
+ PrintBasic.print_basic(self.updated_at, format_data + "Update Time")
+ PrintBasic.print_basic(self.accrued_at, format_data + "Accrued Time")
+ PrintBasic.print_basic(self.interest_rate, format_data + "Interest Rate")
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.state, format_data + "Loan Order State")
diff --git a/huobi/model/margin/margin_account_balance.py b/huobi/model/margin/margin_account_balance.py
new file mode 100644
index 0000000..f5aff02
--- /dev/null
+++ b/huobi/model/margin/margin_account_balance.py
@@ -0,0 +1,41 @@
+from huobi.constant import *
+
+
+class MarginAccountBalance:
+ """
+ The margin order information.
+
+ :member
+ id: Inner id.
+ type: The account type.
+ state: The account state.
+ symbol: The symbol, like "btcusdt".
+ fl_price: The trigger price.
+ fl_type: The trigger type.
+ risk_rate: The risk rate.
+ list:Balance Object list
+ """
+
+ def __init__(self):
+ self.id = 0
+ self.type = AccountType.INVALID
+ self.state = AccountState.INVALID
+ self.symbol = ""
+ self.fl_price = 0.0
+ self.fl_type = 0.0
+ self.risk_rate = 0.0
+ self.list = []
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.type, format_data + "Account Type")
+ PrintBasic.print_basic(self.state, format_data + "Account State")
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.fl_price, format_data + "Trigger Price")
+ PrintBasic.print_basic(self.fl_type, format_data + "Trigger Type")
+ PrintBasic.print_basic(self.risk_rate, format_data + "Risk Rate")
+ if self.list and len(self.list):
+ for balance_obj in self.list:
+ balance_obj.print_object("\t")
+ print()
\ No newline at end of file
diff --git a/huobi/model/margin/margin_loan_ino.py b/huobi/model/margin/margin_loan_ino.py
new file mode 100644
index 0000000..e7f3e48
--- /dev/null
+++ b/huobi/model/margin/margin_loan_ino.py
@@ -0,0 +1,40 @@
+from huobi.model.margin.loan_ino import LoanInfo
+from huobi.utils import default_parse_list_dict
+
+
+class MarginLoanInfo:
+ """
+ The margin loan info.
+
+ :member
+ symbol: symbol like "btcusdt"
+ currencies: loan info for currency in symbol
+ """
+
+ def __init__(self):
+ self.symbol = ""
+ self.currencies = list()
+
+ @staticmethod
+ def json_parse(json_data):
+ retList = []
+ for idx, item in enumerate(json_data):
+ margin_loan_obj = MarginLoanInfo()
+ margin_loan_obj.symbol = item.get("symbol", "")
+
+ currencies_json = item.get("currencies")
+ result_list = default_parse_list_dict(currencies_json, LoanInfo, [])
+
+ margin_loan_obj.currencies = result_list
+
+ retList.append(margin_loan_obj)
+
+ return retList
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ if self.currencies and len(self.currencies):
+ for currency_item in self.currencies:
+ currency_item.print_object("\t")
+ print()
diff --git a/huobi/model/market/__init__.py b/huobi/model/market/__init__.py
new file mode 100644
index 0000000..ffb0366
--- /dev/null
+++ b/huobi/model/market/__init__.py
@@ -0,0 +1,26 @@
+from huobi.model.market.candlestick import Candlestick
+from huobi.model.market.candlestick_event import CandlestickEvent
+from huobi.model.market.candlestick_req import CandlestickReq
+from huobi.model.market.last_trade_bestquote import LastTradeAndBestQuote
+from huobi.model.market.pricedepth import PriceDepth
+from huobi.model.market.pricedepth_event import PriceDepthEvent
+from huobi.model.market.pricedepth_req import PriceDepthReq
+from huobi.model.market.pricedepth_bbo import PriceDepthBbo
+from huobi.model.market.pricedepth_bbo_event import PriceDepthBboEvent
+from huobi.model.market.market_detail_merged import MarketDetailMerged
+from huobi.model.market.market_detail import MarketDetail
+from huobi.model.market.market_detail_event import MarketDetailEvent
+from huobi.model.market.market_detail_req import MarketDetailReq
+from huobi.model.market.trade import Trade
+from huobi.model.market.trade_detail import TradeDetail
+from huobi.model.market.trade_detail_event import TradeDetailEvent
+from huobi.model.market.trade_detail_req import TradeDetailReq
+from huobi.model.market.market_ticker import MarketTicker
+from huobi.model.market.depth_entry import DepthEntry
+from huobi.model.market.mbp import Mbp
+from huobi.model.market.mbp_increase_event import MbpIncreaseEvent
+from huobi.model.market.mbp_full_event import MbpFullEvent
+from huobi.model.market.mbp_req import MbpReq
+
+
+
diff --git a/huobi/model/market/candlestick.py b/huobi/model/market/candlestick.py
new file mode 100644
index 0000000..2bfdc61
--- /dev/null
+++ b/huobi/model/market/candlestick.py
@@ -0,0 +1,41 @@
+
+class Candlestick:
+ """
+ The candlestick/kline data.
+
+ :member
+ id : keep the original timestamp
+ timestamp: The UNIX formatted timestamp in UTC.
+ high: The high price.
+ low: The low price.
+ open: The opening price.
+ close: The closing price.
+ amount: The aggregated trading volume in USDT.
+ count: The number of completed trades. it returns 0 when get ETF candlestick
+ vol: The trading volume in base currency.
+
+ """
+
+ def __init__(self):
+ self.id = 0
+ #self.timestamp = 0
+ self.high = 0.0
+ self.low = 0.0
+ self.open = 0.0
+ self.close = 0.0
+ self.amount = 0.0
+ self.count = 0
+ self.vol = 0.0 #self.volume = 0.0
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "Id")
+ #PrintBasic.print_basic(self.timestamp, format_data + "Unix Time")
+ PrintBasic.print_basic(self.high, format_data + "High")
+ PrintBasic.print_basic(self.low, format_data + "Low")
+ PrintBasic.print_basic(self.open, format_data + "Open")
+ PrintBasic.print_basic(self.close, format_data + "Close")
+ PrintBasic.print_basic(self.count, format_data + "Count")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.vol, format_data + "Volume")
\ No newline at end of file
diff --git a/huobi/model/market/candlestick_event.py b/huobi/model/market/candlestick_event.py
new file mode 100644
index 0000000..47784bb
--- /dev/null
+++ b/huobi/model/market/candlestick_event.py
@@ -0,0 +1,26 @@
+from huobi.constant import *
+from huobi.model.market import *
+
+
+class CandlestickEvent:
+ """
+ The candlestick/kline data received by subscription of candlestick/kline.
+
+ :member
+ ch: the topic you subscribed
+ ts: the UNIX formatted timestamp generated by server in UTC.
+ tick: the data of candlestick/kline.
+ """
+
+ def __init__(self):
+ self.ch = ""
+ self.ts = 0
+ self.tick = Candlestick()
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ts, format_data + "Unix Time")
+ PrintBasic.print_basic(self.ch, format_data + "Channel")
+ if self.tick:
+ self.tick.print_object()
diff --git a/huobi/model/market/candlestick_req.py b/huobi/model/market/candlestick_req.py
new file mode 100644
index 0000000..db4d625
--- /dev/null
+++ b/huobi/model/market/candlestick_req.py
@@ -0,0 +1,27 @@
+from huobi.constant import *
+
+class CandlestickReq:
+ """
+ The candlestick/kline data received by subscription of candlestick/kline.
+
+ :member
+ rep: the Channel or topic you subscribed.
+ id: the UNIX formatted timestamp generated by server in UTC.
+ data: the data of candlestick/kline.
+
+ """
+
+ def __init__(self):
+ self.rep = ""
+ self.id = 0
+ self.data = list()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.rep, format_data + "Channel")
+ PrintBasic.print_basic(self.id, format_data + "Unix Time")
+ print()
+ if len(self.data):
+ for row in self.data:
+ row.print_object()
+ print()
\ No newline at end of file
diff --git a/huobi/model/market/depth_entry.py b/huobi/model/market/depth_entry.py
new file mode 100644
index 0000000..e043789
--- /dev/null
+++ b/huobi/model/market/depth_entry.py
@@ -0,0 +1,25 @@
+
+class DepthEntry:
+ """
+ An depth entry consisting of price and amount.
+
+ :member
+ price: The price of the depth.
+ amount: The amount of the depth.
+ """
+
+ def __init__(self):
+ self.price = 0.0
+ self.amount = 0.0
+
+ @staticmethod
+ def json_parse(data_array):
+ entry = DepthEntry()
+ entry.price = data_array[0]
+ entry.amount = data_array[1]
+ return entry
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.price, format_data + "Price")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
\ No newline at end of file
diff --git a/huobi/model/market/last_trade_bestquote.py b/huobi/model/market/last_trade_bestquote.py
new file mode 100644
index 0000000..88977fe
--- /dev/null
+++ b/huobi/model/market/last_trade_bestquote.py
@@ -0,0 +1,22 @@
+class LastTradeAndBestQuote:
+ """
+ The last trade and best bid/ask.
+
+ :member
+ last_trade_price: The last trade price.
+ last_trade_amount: The last trade amount.
+ ask_price: The best ask price.
+ ask_amount: The best ask amount.
+ bid_price: The best bid price.
+ bid_amount: The best bid amount.
+
+ """
+
+ def __init__(self):
+ self.last_trade_price = 0.0
+ self.last_trade_amount = 0.0
+ self.ask_price = 0.0
+ self.ask_amount = 0.0
+ self.bid_price = 0.0
+ self.bid_amount = 0.0
+
diff --git a/huobi/model/market/market_detail.py b/huobi/model/market/market_detail.py
new file mode 100644
index 0000000..094b3de
--- /dev/null
+++ b/huobi/model/market/market_detail.py
@@ -0,0 +1,38 @@
+class MarketDetail:
+ """
+ The summary of trading in the market for the last 24 hours
+
+ :member
+ id: response ID
+ open: The opening price of last 24 hours.
+ close: The last price of last 24 hours.
+ amount: The aggregated trading volume in USDT.
+ high: The high price of last 24 hours.
+ low: The low price of last 24 hours.
+ count: The number of completed trades.
+ volume: The trading volume in base currency of last 24 hours.
+ version: inner data
+ """
+
+ def __init__(self):
+ self.id = 0
+ self.open = 0.0
+ self.close = 0.0
+ self.amount = 0.0
+ self.high = 0.0
+ self.low = 0.0
+ self.count = 0
+ self.vol = 0.0
+ self.version = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.open, format_data + "Open")
+ PrintBasic.print_basic(self.close, format_data + "Close")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.high, format_data + "High")
+ PrintBasic.print_basic(self.low, format_data + "Low")
+ PrintBasic.print_basic(self.count, format_data + "Count")
+ PrintBasic.print_basic(self.vol, format_data + "Volume")
+ # PrintBasic.print_basic(self.version, format_data + "Version")
\ No newline at end of file
diff --git a/huobi/model/market/market_detail_event.py b/huobi/model/market/market_detail_event.py
new file mode 100644
index 0000000..3f70ca4
--- /dev/null
+++ b/huobi/model/market/market_detail_event.py
@@ -0,0 +1,22 @@
+from huobi.model.market.market_detail import MarketDetail
+
+class MarketDetailEvent:
+ """
+ The 24H trade statistics received by subscription of trade statistics.
+
+ :member
+ Channel: topic you subscribe, include symbol.
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ trade_statistics: The trade statistics.
+ """
+
+ def __init__(self):
+ self.ch = ""
+ self.ts = 0
+ self.tick = MarketDetail()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ch, format_data + "Channel")
+ PrintBasic.print_basic(self.ts, format_data + "Timestamp")
+ self.tick.print_object()
\ No newline at end of file
diff --git a/huobi/model/market/market_detail_merged.py b/huobi/model/market/market_detail_merged.py
new file mode 100644
index 0000000..5fe8ab4
--- /dev/null
+++ b/huobi/model/market/market_detail_merged.py
@@ -0,0 +1,41 @@
+
+class MarketDetailMerged:
+ """
+ The best bid/ask consisting of price and amount.
+
+ :member
+ timestamp: The Unix formatted timestamp in UTC.
+ bid_price: The best bid price.
+ bid_amount: The best bid amount.
+ ask_price: The best ask price.
+ ask_amount: The best ask amount.
+
+ """
+
+ def __init__(self):
+ self.amount = 0
+ self.open = 0.0
+ self.close = 0.0
+ self.high = 0.0
+ self.id = 0
+ self.count = 0.0
+ self.low = 0.0
+ self.version = 0
+ self.ask = []
+ self.vol = 0.0
+ self.bid = []
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ # PrintBasic.print_basic(self.version, format_data + "Version")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.count, format_data + "Count")
+ PrintBasic.print_basic(self.vol, format_data + "Volume")
+
+ PrintBasic.print_basic(self.open, format_data + "Open")
+ PrintBasic.print_basic(self.close, format_data + "Close")
+ PrintBasic.print_basic(self.high, format_data + "High")
+ PrintBasic.print_basic(self.low, format_data + "Low")
+
+ print("Ask", self.ask)
+ print("Bid", self.bid)
\ No newline at end of file
diff --git a/huobi/model/market/market_detail_req.py b/huobi/model/market/market_detail_req.py
new file mode 100644
index 0000000..1b73809
--- /dev/null
+++ b/huobi/model/market/market_detail_req.py
@@ -0,0 +1,22 @@
+from huobi.model.market.market_detail import MarketDetail
+
+class MarketDetailReq:
+ """
+ The 24H trade statistics received by request of trade statistics only once.
+
+ :member
+ rep: The topic you subscribed.
+ ts: The UNIX formatted timestamp generated by server in UTC.
+ trade_statistics: The trade statistics.
+ """
+
+ def __init__(self):
+ self.rep = 0
+ self.ts = 0
+ self.data = MarketDetail()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ts, format_data + "Timestamp")
+ PrintBasic.print_basic(self.rep, format_data + "Channel")
+ self.data.print_object()
\ No newline at end of file
diff --git a/huobi/model/market/market_ticker.py b/huobi/model/market/market_ticker.py
new file mode 100644
index 0000000..d9662da
--- /dev/null
+++ b/huobi/model/market/market_ticker.py
@@ -0,0 +1,47 @@
+class MarketTicker:
+ """
+ The ticker information.
+
+ :member
+ amount: The aggregated trading volume in last 24 hours (rotating 24h).
+ count: The number of completed trades of last 24 hours (rotating 24h).
+ open: The opening price of a nature day (Singapore time).
+ close: The last price of a nature day (Singapore time).
+ low: The low price of a nature day (Singapore time).
+ high: The high price of a nature day (Singapore time).
+ vol: The aggregated trading value in last 24 hours (rotating 24h).
+ symbol: The trading symbol of this object, e.g. btcusdt, bccbtc.
+ bid: Best bid price.
+ bidSize: Best bid size.
+ ask: Best ask price.
+ askSize: Best ask size.
+ """
+
+ def __init__(self):
+ self.amount = 0.0
+ self.count = 0
+ self.open = 0.0
+ self.close = 0.0
+ self.low = 0.0
+ self.high = 0.0
+ self.vol = 0.0
+ self.symbol = ""
+ self.bid = 0.0
+ self.bidSize = 0.0
+ self.ask = 0.0
+ self.askSize = 0.0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.count, format_data + "Count")
+ PrintBasic.print_basic(self.open, format_data + "Opening Price")
+ PrintBasic.print_basic(self.close, format_data + "Last Price")
+ PrintBasic.print_basic(self.low, format_data + "Low Price")
+ PrintBasic.print_basic(self.high, format_data + "High Price")
+ PrintBasic.print_basic(self.vol, format_data + "Vol")
+ PrintBasic.print_basic(self.symbol, format_data + "Trading Symbol")
+ PrintBasic.print_basic(self.bid, format_data + "Best Bid Price")
+ PrintBasic.print_basic(self.bidSize, format_data + "Best Bid Size")
+ PrintBasic.print_basic(self.ask, format_data + "Best Ask Price")
+ PrintBasic.print_basic(self.askSize, format_data + "Best Ask Size")
\ No newline at end of file
diff --git a/huobi/model/market/mbp.py b/huobi/model/market/mbp.py
new file mode 100644
index 0000000..fb962cc
--- /dev/null
+++ b/huobi/model/market/mbp.py
@@ -0,0 +1,54 @@
+
+
+from huobi.model.market.depth_entry import DepthEntry
+
+class Mbp:
+ """
+ Increasement of price depth information.
+
+ :member
+ seqNum: current seqNum.
+ prevSeqNum: previous seqNum.
+ bids: The list of the bid depth. The content is DepthEntry class.
+ asks: The list of the ask depth. The content is DepthEntry class.
+
+ """
+ def __init__(self):
+ self.seqNum = 0
+ self.prevSeqNum = 0
+ self.bids = list()
+ self.asks = list()
+
+ @staticmethod
+ def json_parse(json_data):
+ mbp = Mbp()
+ bid_list = list()
+ mbp.seqNum = json_data.get("seqNum", 0)
+ mbp.prevSeqNum = json_data.get("prevSeqNum", 0) # prevSeqNum only for increased subscribe, request doesn't have this value
+ for item in json_data.get("bids", []):
+ depth_entry = DepthEntry()
+ depth_entry.price = item[0]
+ depth_entry.amount = item[1]
+ bid_list.append(depth_entry)
+ ask_list = list()
+ for item in json_data.get("asks", []):
+ depth_entry = DepthEntry()
+ depth_entry.price = item[0]
+ depth_entry.amount = item[1]
+ ask_list.append(depth_entry)
+ mbp.bids = bid_list
+ mbp.asks = ask_list
+
+ return mbp
+
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.seqNum, format_data + "seqNum")
+ PrintBasic.print_basic(self.prevSeqNum, format_data + "prevSeqNum")
+ for entry in self.bids:
+ PrintBasic.print_basic(str(entry.price) + ", amount: " + str(entry.amount), format_data + "Bids price: ")
+
+ for entry in self.asks:
+ PrintBasic.print_basic(str(entry.price) + ", amount: " + str(entry.amount), format_data + "Asks price: ")
diff --git a/huobi/model/market/mbp_full_event.py b/huobi/model/market/mbp_full_event.py
new file mode 100644
index 0000000..e70112e
--- /dev/null
+++ b/huobi/model/market/mbp_full_event.py
@@ -0,0 +1,33 @@
+from huobi.model.market import Mbp
+
+
+class MbpFullEvent:
+ """
+ full price depth.
+
+ :member
+ ch: Topic of subscribed.
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ data: The price depth.
+
+ """
+
+ def __init__(self):
+ self.ch = ""
+ self.ts = 0
+ self.data = Mbp()
+
+ @staticmethod
+ def json_parse(json_data):
+ mbp_event = MbpFullEvent()
+ mbp_event.ts = json_data.get("ts")
+ mbp_event.ch = json_data.get("ch")
+ mbp = Mbp.json_parse(json_data.get("tick", {}))
+ mbp_event.data = mbp
+ return mbp_event
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ch, format_data + "Topic")
+ PrintBasic.print_basic(self.ts, format_data + "Timestamp")
+ self.data.print_object(format_data + "\t")
\ No newline at end of file
diff --git a/huobi/model/market/mbp_increase_event.py b/huobi/model/market/mbp_increase_event.py
new file mode 100644
index 0000000..c60da0b
--- /dev/null
+++ b/huobi/model/market/mbp_increase_event.py
@@ -0,0 +1,34 @@
+from huobi.model.market import Mbp
+
+
+class MbpIncreaseEvent:
+ """
+ increasement of price depth.
+
+ :member
+ ch: Topic of subscribed.
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ data: The price depth.
+
+ """
+
+ def __init__(self):
+ self.ch = ""
+ self.ts = 0
+ self.data = Mbp()
+
+ @staticmethod
+ def json_parse(json_data):
+ mbp_event = MbpIncreaseEvent()
+ mbp_event.ts = json_data.get("ts")
+ mbp_event.ch = json_data.get("ch")
+ mbp = Mbp.json_parse(json_data.get("tick", {}))
+ mbp_event.data = mbp
+ return mbp_event
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ch, format_data + "Topic")
+ PrintBasic.print_basic(self.ts, format_data + "Timestamp")
+
+ self.data.print_object(format_data + "\t")
diff --git a/huobi/model/market/mbp_req.py b/huobi/model/market/mbp_req.py
new file mode 100644
index 0000000..31f4fd9
--- /dev/null
+++ b/huobi/model/market/mbp_req.py
@@ -0,0 +1,36 @@
+from huobi.model.market import Mbp, PriceDepth
+
+
+class MbpReq:
+ """
+ The market price depth.
+
+ :member
+ rep: request Topic
+ id: The UNIX formatted timestamp generated by server in UTC.
+ data: The price depth.
+ """
+
+ def __init__(self):
+ self.rep = ""
+ self.id = ""
+
+ self.data = Mbp()
+
+
+ @staticmethod
+ def json_parse(data_json):
+ mbp_event = MbpReq()
+ mbp_event.id = data_json.get("id")
+ mbp_event.rep = data_json.get("rep")
+ data = data_json.get("data", {})
+ mbp = Mbp.json_parse(data)
+ mbp_event.data = mbp
+ return mbp_event
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.rep, format_data + "Topic")
+ PrintBasic.print_basic(self.id, format_data + "Timestamp")
+
+ self.data.print_object(format_data + "\t")
diff --git a/huobi/model/market/pricedepth.py b/huobi/model/market/pricedepth.py
new file mode 100644
index 0000000..814a120
--- /dev/null
+++ b/huobi/model/market/pricedepth.py
@@ -0,0 +1,59 @@
+from huobi.model.market.depth_entry import DepthEntry
+
+
+class PriceDepth:
+ """
+ The price depth information.
+
+ :member
+ ts: The UNIX formatted timestamp in UTC.
+ version:
+ bids: The list of the bid depth. The content is DepthEntry class.
+ asks: The list of the ask depth. The content is DepthEntry class.
+
+ """
+ def __init__(self):
+ self.ts = 0
+ self.version = 0
+ self.bids = list()
+ self.asks = list()
+
+ @staticmethod
+ def json_parse(dict_data):
+ price_depth_obj = PriceDepth()
+ price_depth_obj.ts = dict_data.get("ts")
+ price_depth_obj.version = dict_data.get("version")
+ bid_list = list()
+ bids_array = dict_data.get("bids", [])
+ for item in bids_array:
+ depth_entry = DepthEntry.json_parse(item)
+ bid_list.append(depth_entry)
+ ask_list = list()
+ asks_array = dict_data.get("asks", [])
+ for item in asks_array:
+ depth_entry = DepthEntry.json_parse(item)
+ ask_list.append(depth_entry)
+ price_depth_obj.bids = bid_list
+ price_depth_obj.asks = ask_list
+
+ return price_depth_obj
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ts, format_data + "UTC Time")
+ PrintBasic.print_basic(self.version, format_data + "Version")
+ if len(self.bids):
+ i = 0
+ print(format_data, "---- Top " + str(len(self.bids)) + " bids ----")
+ for entry in self.bids:
+ i = i + 1
+ print(format_data, str(i) + ": price: " + str(entry.price) + ", amount: " + str(entry.amount))
+ #print()
+
+ if len(self.asks):
+ i = 0
+ print(format_data, "---- Top " + str(len(self.asks)) + " asks ----")
+ for entry in self.asks:
+ i = i + 1
+ print(format_data, str(i) + ": price: " + str(entry.price) + ", amount: " + str(entry.amount))
+ #print()
\ No newline at end of file
diff --git a/huobi/model/market/pricedepth_bbo.py b/huobi/model/market/pricedepth_bbo.py
new file mode 100644
index 0000000..001a1b7
--- /dev/null
+++ b/huobi/model/market/pricedepth_bbo.py
@@ -0,0 +1,34 @@
+
+class PriceDepthBbo:
+ """
+ The price depth information.
+
+ :member
+ timestamp: The UNIX formatted timestamp in UTC.
+ bid: the first bid near trade value.
+ bidSize: the bid size.
+ ask: The first ask near trade value.
+ askSize: the ask size.
+ quoteTime : quote time
+ symbol : trade symbol
+
+
+ """
+ def __init__(self):
+ self.seqId = 0
+ self.ask = 0.0
+ self.askSize = 0.0
+ self.bid = 0.0
+ self.bidSize = 0.0
+ self.quoteTime = 0
+ self.symbol = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.seqId, format_data + "Seq ID")
+ PrintBasic.print_basic(self.ask, format_data + "Ask")
+ PrintBasic.print_basic(self.askSize, format_data + "Ask Size")
+ PrintBasic.print_basic(self.bid, format_data + "Bid")
+ PrintBasic.print_basic(self.bidSize, format_data + "Bid Size")
+ PrintBasic.print_basic(self.quoteTime, format_data + "Quote Time")
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
\ No newline at end of file
diff --git a/huobi/model/market/pricedepth_bbo_event.py b/huobi/model/market/pricedepth_bbo_event.py
new file mode 100644
index 0000000..f65d560
--- /dev/null
+++ b/huobi/model/market/pricedepth_bbo_event.py
@@ -0,0 +1,25 @@
+from huobi.model.market import PriceDepthBbo
+
+
+class PriceDepthBboEvent:
+ """
+ The price depth received by subscription of price depth.
+
+ :member
+ symbol: The symbol you subscribed.
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ data: The price depth.
+
+ """
+
+ def __init__(self):
+ self.ts = 0
+ self.ch = ""
+ self.tick = PriceDepthBbo()
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ts, format_data + "Time")
+ PrintBasic.print_basic(self.ch, format_data + "Channel")
+ self.tick.print_object(format_data)
\ No newline at end of file
diff --git a/huobi/model/market/pricedepth_event.py b/huobi/model/market/pricedepth_event.py
new file mode 100644
index 0000000..aa960be
--- /dev/null
+++ b/huobi/model/market/pricedepth_event.py
@@ -0,0 +1,23 @@
+
+from huobi.model.market.pricedepth import PriceDepth
+class PriceDepthEvent:
+ """
+ The price depth information.
+
+ :member
+ ts: The UNIX formatted timestamp in UTC.
+ version:
+ bids: The list of the bid depth. The content is DepthEntry class.
+ asks: The list of the ask depth. The content is DepthEntry class.
+
+ """
+ def __init__(self):
+ self.ch = ""
+ self.tick = PriceDepth()
+
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ch, format_data + "Channel")
+ self.tick.print_object("\t")
\ No newline at end of file
diff --git a/huobi/model/market/pricedepth_req.py b/huobi/model/market/pricedepth_req.py
new file mode 100644
index 0000000..f04f993
--- /dev/null
+++ b/huobi/model/market/pricedepth_req.py
@@ -0,0 +1,22 @@
+
+from huobi.model.market.pricedepth import PriceDepth
+
+class PriceDepthReq:
+ """
+ The price depth information.
+
+ :member
+ ts: The UNIX formatted timestamp in UTC.
+ version:
+ bids: The list of the bid depth. The content is DepthEntry class.
+ asks: The list of the ask depth. The content is DepthEntry class.
+
+ """
+ def __init__(self):
+ self.rep = ""
+ self.data = PriceDepth()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.rep, format_data + "Channel")
+ self.data.print_object("\t")
\ No newline at end of file
diff --git a/huobi/model/market/trade.py b/huobi/model/market/trade.py
new file mode 100644
index 0000000..e621ed0
--- /dev/null
+++ b/huobi/model/market/trade.py
@@ -0,0 +1,29 @@
+
+class Trade:
+ """
+ The trade information with price and amount etc.
+
+ :member
+ price: The trading price in quote currency.
+ amount: The trading volume in base currency.
+ trade_id: The unique trade id of this trade.
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ direction: The direction of the taker trade: 'buy' or 'sell'.
+ """
+
+ def __init__(self):
+ self.price = 0.0
+ self.amount = 0.0
+ self.trade_id = 0
+ self.ts = 0
+ self.direction = ""
+
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.trade_id, format_data + "Trade Id")
+ PrintBasic.print_basic(self.ts, format_data + "Trade Time")
+ PrintBasic.print_basic(self.price, format_data + "Price")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.direction, format_data + "Direction")
\ No newline at end of file
diff --git a/huobi/model/market/trade_detail.py b/huobi/model/market/trade_detail.py
new file mode 100644
index 0000000..629db66
--- /dev/null
+++ b/huobi/model/market/trade_detail.py
@@ -0,0 +1,29 @@
+
+class TradeDetail:
+ """
+ The trade information with price and amount etc.
+
+ :member
+ price: The trading price in quote currency.
+ amount: The trading volume in base currency.
+ tradeId: The unique trade id of this trade.
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ direction: The direction of the taker trade: 'buy' or 'sell'.
+ """
+
+ def __init__(self):
+ self.price = 0.0
+ self.amount = 0.0
+ self.tradeId = 0
+ self.ts = 0
+ self.direction = ""
+
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.tradeId, format_data + "Trade Id")
+ PrintBasic.print_basic(self.ts, format_data + "Trade Time")
+ PrintBasic.print_basic(self.price, format_data + "Price")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.direction, format_data + "Direction")
\ No newline at end of file
diff --git a/huobi/model/market/trade_detail_event.py b/huobi/model/market/trade_detail_event.py
new file mode 100644
index 0000000..ef16073
--- /dev/null
+++ b/huobi/model/market/trade_detail_event.py
@@ -0,0 +1,28 @@
+
+
+class TradeDetailEvent:
+ """
+ The trade received by subscription of trade.
+
+ :member
+ symbol: The symbol you subscribed.
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ trade_list: The trade list. The content is Trade class.
+ """
+
+ def __init__(self):
+ self.ch = ""
+ self.id = 0
+ self.ts = 0
+ self.data = list()
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ch, format_data + "Channel")
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.ts, format_data + "Unix Time")
+ if len(self.data):
+ for trade_detail in self.data:
+ trade_detail.print_object()
+ print()
\ No newline at end of file
diff --git a/huobi/model/market/trade_detail_req.py b/huobi/model/market/trade_detail_req.py
new file mode 100644
index 0000000..8aa1e29
--- /dev/null
+++ b/huobi/model/market/trade_detail_req.py
@@ -0,0 +1,23 @@
+
+
+class TradeDetailReq:
+ """
+ The trade received by subscription of trade.
+
+ :member
+ rep: The Channel you subscribed.
+ trade_list: The trade list. The content is Trade class.
+ """
+
+ def __init__(self):
+ self.rep = ""
+ self.data = list()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.rep, format_data + "Channel")
+ print()
+ if len(self.data):
+ for trade_detail in self.data:
+ trade_detail.print_object()
+ print()
\ No newline at end of file
diff --git a/huobi/model/subuser/__init__.py b/huobi/model/subuser/__init__.py
new file mode 100644
index 0000000..41bd908
--- /dev/null
+++ b/huobi/model/subuser/__init__.py
@@ -0,0 +1,5 @@
+from huobi.model.subuser.subuser_creation import SubuserCreation
+from huobi.model.subuser.subuser_transferability import SubuserTransferability
+from huobi.model.subuser.subuser_apikey_generation import SubuserApikeyGeneration
+from huobi.model.subuser.user_apikey_info import UserApikeyInfo
+from huobi.model.subuser.subuser_apikey_modification import SubuserApikeyModification
diff --git a/huobi/model/subuser/subuser_apikey_generation.py b/huobi/model/subuser/subuser_apikey_generation.py
new file mode 100644
index 0000000..aad98a3
--- /dev/null
+++ b/huobi/model/subuser/subuser_apikey_generation.py
@@ -0,0 +1,26 @@
+class SubuserApikeyGeneration:
+ """
+ The trade information with price and amount etc.
+
+ :member
+ accessKey:
+ secretKey:
+ note:
+ permission: "trade,readOnly",
+ ipAddresses":
+ """
+
+ def __init__(self):
+ self.accessKey = ""
+ self.secretKey = ""
+ self.note = ""
+ self.permission = ""
+ self.ipAddresses = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.accessKey, format_data + "accessKey")
+ PrintBasic.print_basic(self.secretKey, format_data + "secretKey")
+ PrintBasic.print_basic(self.note, format_data + "note")
+ PrintBasic.print_basic(self.permission, format_data + "permission")
+ PrintBasic.print_basic(self.ipAddresses, format_data + "ipAddresses")
diff --git a/huobi/model/subuser/subuser_apikey_modification.py b/huobi/model/subuser/subuser_apikey_modification.py
new file mode 100644
index 0000000..6265e7d
--- /dev/null
+++ b/huobi/model/subuser/subuser_apikey_modification.py
@@ -0,0 +1,20 @@
+class SubuserApikeyModification:
+ """
+ The trade information with price and amount etc.
+
+ :member
+ note:
+ permission: "trade,readOnly",
+ ipAddresses":
+ """
+
+ def __init__(self):
+ self.note = ""
+ self.permission = ""
+ self.ipAddresses = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.note, format_data + "note")
+ PrintBasic.print_basic(self.permission, format_data + "permission")
+ PrintBasic.print_basic(self.ipAddresses, format_data + "ipAddresses")
diff --git a/huobi/model/subuser/subuser_creation.py b/huobi/model/subuser/subuser_creation.py
new file mode 100644
index 0000000..b8f6b88
--- /dev/null
+++ b/huobi/model/subuser/subuser_creation.py
@@ -0,0 +1,27 @@
+
+class SubuserCreation:
+ """
+ The trade information with price and amount etc.
+
+ :member
+ subUid: sub user ID.
+ userState: sub user account state, states see SubUidState.
+ """
+
+ def __init__(self):
+ self.user_name = ""
+ self.note = ""
+ self.uid = 0
+ self.err_code = 0
+ self.err_message = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.user_name, format_data + "userName")
+ PrintBasic.print_basic(self.note, format_data + "note")
+ PrintBasic.print_basic(self.uid, format_data + "uid")
+ PrintBasic.print_basic(self.err_code, format_data + "errCode")
+ PrintBasic.print_basic(self.err_message, format_data + "errMessage")
+
+
+
diff --git a/huobi/model/subuser/subuser_transferability.py b/huobi/model/subuser/subuser_transferability.py
new file mode 100644
index 0000000..a327390
--- /dev/null
+++ b/huobi/model/subuser/subuser_transferability.py
@@ -0,0 +1,20 @@
+
+class SubuserTransferability:
+ """
+ The trade information with price and amount etc.
+
+ :member
+ subUid: sub user ID.
+ userState: sub user account state, states see SubUidState.
+ """
+
+ def __init__(self):
+ self.transferrable = ""
+ self.accountType = ""
+ self.subUid = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.subUid, format_data + "subUid")
+ PrintBasic.print_basic(self.accountType, format_data + "accountType")
+ PrintBasic.print_basic(self.transferrable, format_data + "transferrable")
diff --git a/huobi/model/subuser/trade_market.py b/huobi/model/subuser/trade_market.py
new file mode 100644
index 0000000..74d22b7
--- /dev/null
+++ b/huobi/model/subuser/trade_market.py
@@ -0,0 +1,21 @@
+
+class TradeMarket:
+ """
+ The trade information with price and amount etc.
+
+ :member
+ subUid: sub user ID.
+ accountType:
+ activation: sub user account state for given accountType.
+ """
+
+ def __init__(self):
+ self.sub_uid = ""
+ self.account_type = ""
+ self.activation = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.sub_uid, format_data + "subUid")
+ PrintBasic.print_basic(self.account_type, format_data + "accountType")
+ PrintBasic.print_basic(self.activation, format_data + "activation")
diff --git a/huobi/model/subuser/user_apikey_info.py b/huobi/model/subuser/user_apikey_info.py
new file mode 100644
index 0000000..a55c126
--- /dev/null
+++ b/huobi/model/subuser/user_apikey_info.py
@@ -0,0 +1,37 @@
+class UserApikeyInfo:
+ """
+ The trade information with price and amount etc.
+
+ :member
+ accessKey: .
+ createTime:
+ ipAddresses: .
+ note:
+ permission:
+ status:
+ updateTime:
+ validDays:
+
+ """
+
+ def __init__(self):
+ self.accessKey = ""
+ self.createTime = 0
+ self.ipAddresses = ""
+ self.note = ""
+ self.permission = ""
+ self.status = ""
+ self.updateTime = 0
+ self.validDays = -1
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+
+ PrintBasic.print_basic(self.accessKey, format_data + "accessKey")
+ PrintBasic.print_basic(self.createTime, format_data + "createTime")
+ PrintBasic.print_basic(self.ipAddresses, format_data + "ipAddresses")
+ PrintBasic.print_basic(self.note, format_data + "note")
+ PrintBasic.print_basic(self.permission, format_data + "permission")
+ PrintBasic.print_basic(self.status, format_data + "status")
+ PrintBasic.print_basic(self.updateTime, format_data + "updateTime")
+ PrintBasic.print_basic(self.validDays, format_data + "validDays")
diff --git a/huobi/model/trade/__init__.py b/huobi/model/trade/__init__.py
new file mode 100644
index 0000000..3a83d41
--- /dev/null
+++ b/huobi/model/trade/__init__.py
@@ -0,0 +1,17 @@
+from huobi.model.trade.batch_cancel_result import BatchCancelResult
+from huobi.model.trade.batch_cancel_count import BatchCancelCount
+from huobi.model.trade.feerate import FeeRate
+from huobi.model.trade.matchresult import MatchResult
+from huobi.model.trade.order import Order
+from huobi.model.trade.order_detail_req import OrderDetailReq
+from huobi.model.trade.order_list_item import OrderListItem
+from huobi.model.trade.order_list_req import OrderListReq
+from huobi.model.trade.order_update_event import OrderUpdateEvent
+from huobi.model.trade.order_update import OrderUpdate
+from huobi.model.trade.batch_create_order import BatchCreateOrder
+from huobi.model.trade.transact_feerate import TransactFeeRate
+from huobi.model.trade.trade_clearing import TradeClearing
+from huobi.model.trade.trade_clearing_event import TradeClearingEvent
+
+
+
diff --git a/huobi/model/trade/batch_cancel_count.py b/huobi/model/trade/batch_cancel_count.py
new file mode 100644
index 0000000..bbec6d0
--- /dev/null
+++ b/huobi/model/trade/batch_cancel_count.py
@@ -0,0 +1,23 @@
+
+
+
+class BatchCancelCount:
+ """
+ The result of batch cancel operation.
+
+ :member
+ success_count: The number of cancel request sent successfully.
+ failed_count: The number of cancel request failed.
+ next_id:next open order id
+ """
+
+ def __init__(self):
+ self.success_count = 0
+ self.failed_count = 0
+ self.next_id = -1
+
+ def print_object(self, format_data=""):
+ from huobi.utils import PrintBasic
+ PrintBasic.print_basic(self.success_count, format_data + "Success Count")
+ PrintBasic.print_basic(self.failed_count, format_data + "Failed Count")
+ PrintBasic.print_basic(self.next_id, format_data + "Next Open Order ID")
\ No newline at end of file
diff --git a/huobi/model/trade/batch_cancel_result.py b/huobi/model/trade/batch_cancel_result.py
new file mode 100644
index 0000000..aae02b5
--- /dev/null
+++ b/huobi/model/trade/batch_cancel_result.py
@@ -0,0 +1,17 @@
+class BatchCancelResult:
+ """
+ The result of batch cancel operation.
+
+ :member
+ success_count: The number of cancel request sent successfully.
+ failed_count: The number of cancel request failed.
+
+ """
+
+ def __init__(self):
+ self.success = []
+ self.failed = []
+
+ def print_object(self, format_data=""):
+ print("Success Order Counts", len(self.success), " Success Order Ids : ", self.success)
+ print("Fail Order Counts", len(self.failed), " Fail Order Ids : ", self.failed)
\ No newline at end of file
diff --git a/huobi/model/trade/batch_create_order.py b/huobi/model/trade/batch_create_order.py
new file mode 100644
index 0000000..dc36274
--- /dev/null
+++ b/huobi/model/trade/batch_create_order.py
@@ -0,0 +1,23 @@
+class BatchCreateOrder:
+ """
+ batch create order result
+
+ :member
+ order_id: The transfer id.
+ client_order_id: The crypto currency to deposit.
+ err_code: The on-chain transaction hash.
+ err_msg: The number of crypto asset transferred in its minimum unit.
+
+ """
+ def __init__(self):
+ self.order_id = 0
+ self.client_order_id = ""
+ self.err_code = ""
+ self.err_msg = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils import PrintBasic
+ PrintBasic.print_basic(self.order_id, format_data + "Order Id")
+ PrintBasic.print_basic(self.client_order_id, format_data + "Client Order Id")
+ PrintBasic.print_basic(self.err_code, format_data + "Error Code")
+ PrintBasic.print_basic(self.err_msg, format_data + "Error Message")
\ No newline at end of file
diff --git a/huobi/model/trade/feerate.py b/huobi/model/trade/feerate.py
new file mode 100644
index 0000000..62d0db9
--- /dev/null
+++ b/huobi/model/trade/feerate.py
@@ -0,0 +1,22 @@
+
+class FeeRate:
+ """
+ The account information for spot account, margin account etc.
+
+ :member
+ symbol: The symbol, like "btcusdt".
+ maker_fee: maker fee rate
+ taker_fee: taker fee rate
+
+ """
+
+ def __init__(self):
+ self.symbol = ""
+ self.maker_fee = ""
+ self.taker_fee = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.maker_fee, format_data + "Maker Fee")
+ PrintBasic.print_basic(self.taker_fee, format_data + "Taker Fee")
\ No newline at end of file
diff --git a/huobi/model/trade/matchresult.py b/huobi/model/trade/matchresult.py
new file mode 100644
index 0000000..26f42a6
--- /dev/null
+++ b/huobi/model/trade/matchresult.py
@@ -0,0 +1,58 @@
+from huobi.constant import *
+
+
+class MatchResult:
+ """
+ The match result information.
+
+ :member
+ created_timestamp: The UNIX formatted timestamp in UTC when the match and fill is done.
+ filled_amount: The amount which has been filled.
+ filled_fees: The transaction fee paid so far.
+ id: The internal id.
+ match_id: The match id of this match.
+ order_id: The order id of this order.
+ price: The limit price of limit order.
+ source: The source where the order was triggered, possible values: sys, web, api, app.
+ symbol: The symbol, like "btcusdt".
+ type: The order type, possible values are: buy-market, sell-market, buy-limit, sell-limit,
+ buy-ioc, sell-ioc, buy-limit-maker, sell-limit-maker, buy-limit-fok, sell-limit-fok, buy-stop-limit-fok, sell-stop-limit-fok.
+ filled_points: deduct points
+ fee_deduct_currency: deduct type, it means deduct from HT/ HT points / or other currency
+ fee_currency:
+ """
+
+ def __init__(self):
+ self.created_at = 0
+ self.filled_amount = 0.0
+ self.filled_fees = 0.0
+ self.id = 0
+ self.match_id = 0
+ self.order_id = 0
+ self.price = 0.0
+ self.source = OrderSource.INVALID
+ self.symbol = ""
+ self.type = OrderType.INVALID
+ self.role = ""
+ self.filled_points = ""
+ self.fee_deduct_currency = ""
+ self.fee_currency = ""
+ self.fee_deduct_state = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.created_at, format_data + "Create Time")
+ PrintBasic.print_basic(self.filled_amount, format_data + "Fill Amount")
+ PrintBasic.print_basic(self.filled_fees, format_data + "Fill Fee")
+ PrintBasic.print_basic(self.filled_points, format_data + "Fill Points")
+ PrintBasic.print_basic(self.match_id, format_data + "Match ID")
+ PrintBasic.print_basic(self.order_id, format_data + "Order ID")
+ PrintBasic.print_basic(self.price, format_data + "Price")
+ PrintBasic.print_basic(self.source, format_data + "Source")
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.type, format_data + "Order Type")
+ PrintBasic.print_basic(self.role, format_data + "Role")
+ PrintBasic.print_basic(self.fee_deduct_currency, format_data + "Fee Deduct Currency")
+ PrintBasic.print_basic(self.fee_currency, format_data + "Fee Currency")
+ PrintBasic.print_basic(self.fee_deduct_state, format_data + "Fee Deduct State")
diff --git a/huobi/model/trade/order.py b/huobi/model/trade/order.py
new file mode 100644
index 0000000..00df78b
--- /dev/null
+++ b/huobi/model/trade/order.py
@@ -0,0 +1,86 @@
+from huobi.constant import *
+from huobi.utils.json_parser import fill_obj
+
+
+class Order:
+ """
+ The detail order information.
+
+ :member
+ amount: The amount of base currency in this order.
+ price: The limit price of limit order.
+ created_timestamp: The UNIX formatted timestamp in UTC when the order was created.
+ canceled_timestamp: The UNIX formatted timestamp in UTC when the order was canceled, if not canceled then has value of 0.
+ finished_timestamp: The UNIX formatted timestamp in UTC when the order was changed to a final state. This is not the time the order is matched.
+ order_id: The order id.
+ symbol: The symbol, like "btcusdt".
+ order_type: The order type, possible values are: buy-market, sell-market, buy-limit, sell-limit, buy-ioc, sell-ioc, buy-limit-maker, sell-limit-maker, buy-limit-fok, sell-limit-fok, buy-stop-limit-fok, sell-stop-limit-fok.
+ filled_amount: The amount which has been filled.
+ filled_cash_amount: The filled total in quote currency.
+ filled_fees: The transaction fee paid so far.
+ source: The source where the order was triggered, possible values: sys, web, api, app.
+ state: The order state: submitted, partial-filled, cancelling, filled, canceled.
+ stop_price : stop price used for buy-stop-limit,sell-stop-limit
+ operator : only [gte] and [lte] to trigger buy-stop-limit,sell-stop-limit
+ """
+
+ def __init__(self):
+ self.id = 0
+ self.symbol = ""
+ self.account_id = 0
+ self.amount = 0.0
+ self.price = 0.0
+ self.created_at = 0
+ self.canceled_at = 0
+ self.finished_at = 0
+ self.type = OrderType.INVALID
+ self.filled_amount = 0.0
+ self.filled_cash_amount = 0.0
+ self.filled_fees = 0.0
+ self.source = OrderSource.INVALID
+ self.state = OrderState.INVALID
+ self.client_order_id = ""
+ self.stop_price = ""
+ self.next_time = 0
+ self.operator=""
+
+ @staticmethod
+ def json_parse(json_data):
+ order = fill_obj(json_data, Order)
+ order.filled_amount = json_data.get("filled-amount", json_data.get("field-amount", 0))
+ order.filled_cash_amount = json_data.get("filled-cash-amount", json_data.get("field-cash-amount", 0))
+ order.filled_fees = json_data.get("filled-fees", json_data.get("field-fees", 0))
+ return order
+
+ @staticmethod
+ def json_parse_list(json_data):
+ if json_data and len(json_data):
+ order_list = list()
+ for idx, row in enumerate(json_data):
+ order_item = Order.json_parse(row)
+ order_list.append(order_item)
+ return order_list
+
+ return list()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "Order Id")
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.price, format_data + "Price")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.created_at, format_data + "Create Time")
+ PrintBasic.print_basic(self.canceled_at, format_data + "Cancel Time")
+ PrintBasic.print_basic(self.finished_at, format_data + "Finish Time")
+ PrintBasic.print_basic(self.type, format_data + "Order Type")
+ PrintBasic.print_basic(self.filled_amount, format_data + "Filled Amount")
+ PrintBasic.print_basic(self.filled_cash_amount, format_data + "Filled Cash Amount")
+ PrintBasic.print_basic(self.filled_fees, format_data + "Filled Fees")
+ #PrintBasic.print_basic(self.account_type, format_data + "Account Type")
+ PrintBasic.print_basic(self.source, format_data + "Order Source")
+ PrintBasic.print_basic(self.state, format_data + "Order State")
+ PrintBasic.print_basic(self.client_order_id, format_data + "Client Order Id")
+ PrintBasic.print_basic(self.stop_price, format_data + "Stop Price")
+ PrintBasic.print_basic(self.operator, format_data + "Operator")
+ PrintBasic.print_basic(self.next_time, format_data + "Next Time")
+
diff --git a/huobi/model/trade/order_detail_req.py b/huobi/model/trade/order_detail_req.py
new file mode 100644
index 0000000..4b4ac09
--- /dev/null
+++ b/huobi/model/trade/order_detail_req.py
@@ -0,0 +1,29 @@
+from huobi.model.trade.order_list_item import OrderListItem
+
+
+class OrderDetailReq:
+ """
+ The order update received by subscription of order update.
+
+ :member
+ symbol: The symbol you subscribed.
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ topic : request topic
+ client_req_id : client request id
+ data: The order detail.
+
+ """
+
+ def __init__(self):
+ self.ts = 0
+ self.topic = ""
+ self.cid = ""
+ self.data = OrderListItem()
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ts, format_data + "Timestamp")
+ PrintBasic.print_basic(self.cid, format_data + "Client Req ID")
+ PrintBasic.print_basic(self.topic, format_data + "Topic")
+ self.data.print_object("\t")
\ No newline at end of file
diff --git a/huobi/model/trade/order_list_item.py b/huobi/model/trade/order_list_item.py
new file mode 100644
index 0000000..c790d0a
--- /dev/null
+++ b/huobi/model/trade/order_list_item.py
@@ -0,0 +1,55 @@
+
+from huobi.constant import *
+
+class OrderListItem:
+ """
+ The order update received by request of order list.
+
+ :member
+ symbol: The symbol you subscribed.
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ topic: request topic
+ client_req_id: client request ID
+ order_list : order list
+
+ """
+
+ def __init__(self):
+ self.id = 0
+ self.symbol = ""
+ self.account_id = 0
+ self.amount = 0.0
+ self.price = 0.0
+ self.created_at = 0
+ self.type = OrderType.INVALID
+ self.finished_at = 0
+ self.source = OrderSource.INVALID
+ self.state = OrderState.INVALID
+ self.canceled_at = 0
+ self.filled_amount = 0.0
+ self.filled_cash_amount = 0.0
+ self.filled_fees = 0.0
+ self.stop_price = 0.0
+ self.operator = ""
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.account_id, format_data + "Account Id")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.price, format_data + "Price")
+ PrintBasic.print_basic(self.created_at, format_data + "Create Time")
+ PrintBasic.print_basic(self.type, format_data + "Order Type")
+ PrintBasic.print_basic(self.finished_at, format_data + "Finish Time")
+ PrintBasic.print_basic(self.source, format_data + "Order Source")
+ PrintBasic.print_basic(self.state, format_data + "Order State")
+ PrintBasic.print_basic(self.canceled_at, format_data + "Cancel Time")
+ PrintBasic.print_basic(self.filled_amount, format_data + "Filled Amount")
+ PrintBasic.print_basic(self.filled_cash_amount, format_data + "Filled Cash Amount")
+ PrintBasic.print_basic(self.filled_fees, format_data + "Filled Fees")
+ PrintBasic.print_basic(self.stop_price, format_data + "Stop Price")
+ PrintBasic.print_basic(self.operator, format_data + "Operator")
+
+
diff --git a/huobi/model/trade/order_list_req.py b/huobi/model/trade/order_list_req.py
new file mode 100644
index 0000000..dddf0b0
--- /dev/null
+++ b/huobi/model/trade/order_list_req.py
@@ -0,0 +1,29 @@
+
+class OrderListReq:
+ """
+ The order update received by request of order list.
+
+ :member
+ symbol: The symbol you subscribed.
+ timestamp: The UNIX formatted timestamp generated by server in UTC.
+ topic: request topic
+ data : OrderListItem
+
+ """
+
+ def __init__(self):
+ self.ts = 0
+ self.topic = ""
+ self.data = list()
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ts, format_data + "Timestamp")
+ PrintBasic.print_basic(self.topic, format_data + "Channel")
+ print("Order List as below : count " + str(len(self.data)))
+ if len(self.data):
+ for orderlistitem_obj in self.data:
+ orderlistitem_obj.print_object("\t ")
+ print()
+
diff --git a/huobi/model/trade/order_update.py b/huobi/model/trade/order_update.py
new file mode 100644
index 0000000..fdbf747
--- /dev/null
+++ b/huobi/model/trade/order_update.py
@@ -0,0 +1,56 @@
+from huobi.constant import *
+
+
+class OrderUpdate:
+ """
+ The detail order information.
+
+ :member
+ orderId: The order id.
+ tradePrice: trade price
+ tradeVolume: trade volume
+ tradeId: Id record for trade
+ tradeTime: trade timestamp (ms)
+ aggressor: true (taker), false (maker)
+ remainAmt: Remaining amount (for buy-market order it's remaining value)
+ orderStatus: Order status, valid value: partial-filled, filled
+ clientOrderId: Client order ID (if any)
+ eventType: Event type, valid value: trade
+ symbol: The symbol, like "btcusdt".
+ type: The order type, possible values are: buy-market, sell-market, buy-limit, sell-limit, buy-ioc, sell-ioc, buy-limit-maker, sell-limit-maker, buy-limit-fok, sell-limit-fok.
+ """
+
+ def __init__(self):
+ self.orderId = 0
+ self.tradePrice = ""
+ self.tradeVolume = ""
+ self.tradeId = 0
+ self.tradeTime = 0
+ self.aggressor = False
+ self.remainAmt = ""
+ self.orderStatus = OrderState.INVALID
+ self.clientOrderId = ""
+ self.eventType = ""
+ self.symbol = ""
+ self.type = OrderType.INVALID
+ self.accountId = 0
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.orderId, format_data + "Order Id")
+ PrintBasic.print_basic(self.tradePrice, format_data + "Trade Price")
+ PrintBasic.print_basic(self.tradeVolume, format_data + "Trade Volume")
+ PrintBasic.print_basic(self.tradeId, format_data + "Trade Id")
+ PrintBasic.print_basic(self.tradeTime, format_data + "Trade Timestamp")
+ PrintBasic.print_basic(self.aggressor, format_data + "is Taker")
+ PrintBasic.print_basic(self.orderStatus, format_data + "Order State")
+ PrintBasic.print_basic(self.clientOrderId, format_data + "Client Order Id")
+ PrintBasic.print_basic(self.eventType, format_data + "Event Type")
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.type, format_data + "Order Type")
+ PrintBasic.print_basic(self.accountId, format_data + "Account Id")
+
+
+
+
diff --git a/huobi/model/trade/order_update_event.py b/huobi/model/trade/order_update_event.py
new file mode 100644
index 0000000..8399ec3
--- /dev/null
+++ b/huobi/model/trade/order_update_event.py
@@ -0,0 +1,23 @@
+from huobi.model.trade.order_update import OrderUpdate
+
+
+class OrderUpdateEvent:
+ """
+ The order update received by subscription of order update.
+
+ :member
+ ch: The symbol you subscribed.
+ data: The order detail.
+
+ """
+
+ def __init__(self):
+ self.ch = ""
+ self.data = OrderUpdate()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ch, format_data + "Topic")
+
+ orderupdate = self.data
+ orderupdate.print_object()
\ No newline at end of file
diff --git a/huobi/model/trade/trade_clearing.py b/huobi/model/trade/trade_clearing.py
new file mode 100644
index 0000000..d1f1726
--- /dev/null
+++ b/huobi/model/trade/trade_clearing.py
@@ -0,0 +1,60 @@
+from huobi.constant import *
+from huobi.utils.json_parser import fill_obj, default_parse_list_dict
+
+
+class TradeClearing:
+ """
+ The detail order information.
+
+ :member
+ order_id: The order id.
+ symbol: The symbol, like "btcusdt".
+ tradePrice: trade price.
+ tradeVolume: trade Volume.
+ orderSide: order Side, more to see OrderSide
+ orderType: order type, more to see OrderType
+ aggressor: is aggressor, only true or false
+ tradeId: trade ID.
+ tradeTime: trade Time.
+ transactFee: transact Fee.
+ feeDeduct: Deduct Fee.
+ feeDeductType: fee Deduct Type, current only support ht and point
+ """
+
+ def __init__(self):
+ self.symbol = ""
+ self.orderId = 0
+ self.tradePrice = ""
+ self.tradeVolume = ""
+ self.orderSide = OrderSide.INVALID
+ self.orderType = OrderType.INVALID
+ self.aggressor = False
+ self.tradeId = 0
+ self.tradeTime = 0
+ self.transactFee = ""
+ self.feeDeduct = ""
+ self.feeDeductType = FeeDeductType.INVALID
+
+ @staticmethod
+ def json_parse(json_data):
+ if json_data.get("orderId", None):
+ return default_parse_list_dict(json_data, TradeClearing)
+ else:
+ return TradeClearing()
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.orderId, format_data + "Order Id")
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.tradePrice, format_data + "Trade Price")
+ PrintBasic.print_basic(self.tradeVolume, format_data + "Trade Volume")
+ PrintBasic.print_basic(self.orderSide, format_data + "Order Side")
+ PrintBasic.print_basic(self.orderType, format_data + "Order Type")
+ PrintBasic.print_basic(self.aggressor, format_data + "is Taker")
+ PrintBasic.print_basic(self.tradeId, format_data + "Trade Id")
+ PrintBasic.print_basic(self.tradeTime, format_data + "Trade Time")
+ PrintBasic.print_basic(self.transactFee, format_data + "Transact Fee")
+ PrintBasic.print_basic(self.feeDeduct, format_data + "Fee Deduct")
+ PrintBasic.print_basic(self.feeDeductType, format_data + "Fee Deduct Type")
+
+
diff --git a/huobi/model/trade/trade_clearing_event.py b/huobi/model/trade/trade_clearing_event.py
new file mode 100644
index 0000000..adb64b6
--- /dev/null
+++ b/huobi/model/trade/trade_clearing_event.py
@@ -0,0 +1,32 @@
+from huobi.model.trade import TradeClearing
+
+
+class TradeClearingEvent:
+ """
+ subscribe trading clearing information
+
+ :member
+ action: current is "sub" for subscribe
+ ch: subscribe topic.
+ data: data detail in TradeClearing.
+ """
+
+ def __init__(self):
+ self.action = ""
+ self.ch = ""
+ self.seq = 0
+ self.data = TradeClearing()
+
+ @staticmethod
+ def json_parse(data_json):
+ event_obj = TradeClearingEvent()
+ event_obj.action = data_json.get("action")
+ event_obj.ch = data_json.get("ch")
+ event_obj.seq = data_json.get("seq", 0)
+ event_obj.data = TradeClearing.json_parse(data_json.get("data", {}))
+ return event_obj
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.ch, format_data + "Channel")
+ self.data.print_object()
diff --git a/huobi/model/trade/transact_feerate.py b/huobi/model/trade/transact_feerate.py
new file mode 100644
index 0000000..67c0be5
--- /dev/null
+++ b/huobi/model/trade/transact_feerate.py
@@ -0,0 +1,27 @@
+
+class TransactFeeRate:
+ """
+ The transact fee rate.
+
+ :member
+ symbol: symbol like "btcusdt"
+ makerFeeRate: maker fee rate
+ takerFeeRate: taker fee rate
+ actualMakerRate: actual maker fee rate
+ actualTakerRate: actual taker fee rate
+ """
+
+ def __init__(self):
+ self.symbol = ""
+ self.makerFeeRate = ""
+ self.takerFeeRate = ""
+ self.actualMakerRate = ""
+ self.actualTakerRate = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.symbol, format_data + "Symbol")
+ PrintBasic.print_basic(self.makerFeeRate, format_data + "makerFeeRate")
+ PrintBasic.print_basic(self.takerFeeRate, format_data + "takerFeeRate")
+ PrintBasic.print_basic(self.actualMakerRate, format_data + "actualMakerRate")
+ PrintBasic.print_basic(self.actualTakerRate, format_data + "actualTakerRate")
\ No newline at end of file
diff --git a/huobi/model/wallet/__init__.py b/huobi/model/wallet/__init__.py
new file mode 100644
index 0000000..f351a02
--- /dev/null
+++ b/huobi/model/wallet/__init__.py
@@ -0,0 +1,7 @@
+from huobi.model.wallet.deposit import Deposit
+from huobi.model.wallet.withdraw import Withdraw
+from huobi.model.wallet.chain_deposit_address import ChainDepositAddress
+from huobi.model.wallet.chain_withdraw_address import ChainWithdrawAddress
+from huobi.model.wallet.withdraw_quota import WithdrawQuota
+from huobi.model.wallet.deposit_history import DepositHistory
+from huobi.model.wallet.deposit_history_item import DepositHistoryItem
diff --git a/huobi/model/wallet/chain_deposit_address.py b/huobi/model/wallet/chain_deposit_address.py
new file mode 100644
index 0000000..b2f6ce0
--- /dev/null
+++ b/huobi/model/wallet/chain_deposit_address.py
@@ -0,0 +1,25 @@
+
+class ChainDepositAddress:
+ """
+ The deposit address.
+
+ :member
+ currency: The crypto currency to deposit.
+ address: Deposit address
+ addressTag: Deposit address tag.
+ chain: Block chain name.
+ """
+ def __init__(self):
+ self.currency = ""
+ self.address = ""
+ self.addressTag = ""
+ self.chain = ""
+
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.address, format_data + "Address")
+ PrintBasic.print_basic(self.addressTag, format_data + "addressTag")
+ PrintBasic.print_basic(self.chain, format_data + "Chain")
diff --git a/huobi/model/wallet/chain_withdraw_address.py b/huobi/model/wallet/chain_withdraw_address.py
new file mode 100644
index 0000000..ff16357
--- /dev/null
+++ b/huobi/model/wallet/chain_withdraw_address.py
@@ -0,0 +1,25 @@
+class ChainWithdrawAddress:
+ """
+ The deposit address.
+
+ :member
+ currency: The crypto currency to deposit.
+ address: Deposit address
+ addressTag: Deposit address tag.
+ chain: Block chain name.
+ """
+
+ def __init__(self):
+ self.currency = ""
+ self.address = ""
+ self.addressTag = ""
+ self.chain = ""
+ self.note = ""
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.address, format_data + "Address")
+ PrintBasic.print_basic(self.addressTag, format_data + "addressTag")
+ PrintBasic.print_basic(self.chain, format_data + "Chain")
+ PrintBasic.print_basic(self.note, format_data + "Note")
diff --git a/huobi/model/wallet/deposit.py b/huobi/model/wallet/deposit.py
new file mode 100644
index 0000000..fc6471a
--- /dev/null
+++ b/huobi/model/wallet/deposit.py
@@ -0,0 +1,48 @@
+from huobi.constant import *
+
+
+class Deposit:
+ """
+ The latest status for deposits
+
+ :member
+ id: The transfer id.
+ currency: The crypto currency to deposit.
+ tx_hash: The on-chain transaction hash.
+ amount: The number of crypto asset transferred in its minimum unit.
+ address: The deposit source address.
+ address_tag: The user defined address tag.
+ fee: The amount of fee taken by Huobi in this crypto's minimum unit.
+ created_at: The UNIX formatted timestamp in UTC for the transfer creation.
+ updated_at: The UNIX formatted timestamp in UTC for the transfer's latest update.
+ state: The deposit state of this transfer.
+ """
+
+ def __init__(self):
+ self.id = 0
+ self.type = DepositWithdraw.DEPOSIT
+ self.currency = ""
+ self.tx_hash = ""
+ self.amount = 0.0
+ self.chain = ""
+ self.address = ""
+ self.address_tag = ""
+ self.fee = 0.0
+ self.created_at = 0
+ self.updated_at = 0
+ self.state = DepositState.INVALID
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.type, format_data + "Operate Type")
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.chain, format_data + "Chain")
+ PrintBasic.print_basic(self.tx_hash, format_data + "Trade Hash")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.address, format_data + "Address")
+ PrintBasic.print_basic(self.address_tag, format_data + "Address Tag")
+ PrintBasic.print_basic(self.fee, format_data + "Fee")
+ PrintBasic.print_basic(self.state, format_data + "Deposit State")
+ PrintBasic.print_basic(self.created_at, format_data + "Create Time")
+ PrintBasic.print_basic(self.updated_at, format_data + "Update Time")
diff --git a/huobi/model/wallet/deposit_history.py b/huobi/model/wallet/deposit_history.py
new file mode 100644
index 0000000..7ef4ac8
--- /dev/null
+++ b/huobi/model/wallet/deposit_history.py
@@ -0,0 +1,21 @@
+from huobi.model.wallet.deposit_history_item import DepositHistoryItem
+class DepositHistory:
+ """
+ The deposit history
+
+ :member
+ nextId: next id.
+ data: history list.
+ """
+
+ def __init__(self):
+ self.data = list()
+ self.nextId = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.nextId, format_data + "NextId")
+ if self.data and len(self.data):
+ for item in self.data:
+ item.print_object()
+ PrintBasic.print_basic("", format_data + "")
diff --git a/huobi/model/wallet/deposit_history_item.py b/huobi/model/wallet/deposit_history_item.py
new file mode 100644
index 0000000..9215c9d
--- /dev/null
+++ b/huobi/model/wallet/deposit_history_item.py
@@ -0,0 +1,42 @@
+from huobi.constant import *
+
+
+class DepositHistoryItem:
+ """
+ The deposit history
+
+ :member
+ id: The transfer id.
+ currency: The crypto currency to deposit.
+ txHash: The on-chain transaction hash.
+ amount: The number of crypto asset transferred in its minimum unit.
+ address: The deposit source address.
+ addressTag: The user defined address tag.
+ deposit_state: The deposit state of this transfer.
+ created_timestamp: The UNIX formatted timestamp in UTC for the transfer creation.
+ updated_timestamp: The UNIX formatted timestamp in UTC for the transfer's latest update.
+ """
+ def __init__(self):
+ self.id = 0
+ self.currency = ""
+ self.txHash = ""
+ self.chain = ""
+ self.amount = 0.0
+ self.address = ""
+ self.addressTag = ""
+ self.deposit_state = WithdrawState.INVALID
+ self.created_timestamp = 0
+ self.updated_timestamp = 0
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.chain, format_data + "Chain")
+ PrintBasic.print_basic(self.txHash, format_data + "Trade Hash")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.address, format_data + "Address")
+ PrintBasic.print_basic(self.addressTag, format_data + "Address Tag")
+ PrintBasic.print_basic(self.deposit_state, format_data + "Deposit State")
+ PrintBasic.print_basic(self.created_timestamp, format_data + "Create Time")
+ PrintBasic.print_basic(self.updated_timestamp, format_data + "Update Time")
diff --git a/huobi/model/wallet/withdraw.py b/huobi/model/wallet/withdraw.py
new file mode 100644
index 0000000..24a69d9
--- /dev/null
+++ b/huobi/model/wallet/withdraw.py
@@ -0,0 +1,48 @@
+from huobi.constant import *
+
+
+class Withdraw:
+ """
+ The latest status for withdraws.
+
+ :member
+ id: The transfer id.
+ currency: The crypto currency to deposit.
+ tx_hash: The on-chain transaction hash.
+ amount: The number of crypto asset transferred in its minimum unit.
+ address: The deposit source address.
+ address_tag: The user defined address tag.
+ fee: The amount of fee taken by Huobi in this crypto's minimum unit.
+ created_at: The UNIX formatted timestamp in UTC for the transfer creation.
+ updated_at: The UNIX formatted timestamp in UTC for the transfer's latest update.
+ state: The withdraw state of this transfer.
+ """
+ def __init__(self):
+ self.id = 0
+ self.type = DepositWithdraw.WITHDRAW
+ self.currency = ""
+ self.chain = ""
+ self.tx_hash = ""
+ self.amount = 0.0
+ self.address = ""
+ self.address_tag = ""
+ self.fee = 0.0
+ self.created_at = 0
+ self.updated_at = 0
+ self.state = WithdrawState.INVALID
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.id, format_data + "ID")
+ PrintBasic.print_basic(self.currency, format_data + "Currency")
+ PrintBasic.print_basic(self.type, format_data + "Operator Type")
+ PrintBasic.print_basic(self.chain, format_data + "Chain")
+ PrintBasic.print_basic(self.tx_hash, format_data + "Trade Hash")
+ PrintBasic.print_basic(self.amount, format_data + "Amount")
+ PrintBasic.print_basic(self.address, format_data + "Address")
+ PrintBasic.print_basic(self.address_tag, format_data + "Address Tag")
+ PrintBasic.print_basic(self.fee, format_data + "Fee")
+ PrintBasic.print_basic(self.state, format_data + "Withdraw State")
+ PrintBasic.print_basic(self.created_at, format_data + "Create Time")
+ PrintBasic.print_basic(self.updated_at, format_data + "Update Time")
\ No newline at end of file
diff --git a/huobi/model/wallet/withdraw_quota.py b/huobi/model/wallet/withdraw_quota.py
new file mode 100644
index 0000000..376cc47
--- /dev/null
+++ b/huobi/model/wallet/withdraw_quota.py
@@ -0,0 +1,37 @@
+
+class WithdrawQuota:
+ """
+ Withdraw Quota info.
+
+ :member
+ chain: Block chain name.
+ maxWithdrawAmt: Maximum withdraw amount in each request.
+ withdrawQuotaPerDay: Maximum withdraw amount in a day
+ remainWithdrawQuotaPerDay: Remaining withdraw quota in the day
+ withdrawQuotaPerYear: Maximum withdraw amount in a year
+ remainWithdrawQuotaPerYear: Remaining withdraw quota in the year
+ withdrawQuotaTotal: Maximum withdraw amount in total
+ remainWithdrawQuotaTotal: Remaining withdraw quota in total
+ """
+ def __init__(self):
+ self.chain = ""
+ self.maxWithdrawAmt = ""
+ self.withdrawQuotaPerDay = ""
+ self.remainWithdrawQuotaPerDay = ""
+ self.withdrawQuotaPerYear = ""
+ self.remainWithdrawQuotaPerYear = ""
+ self.withdrawQuotaTotal = ""
+ self.remainWithdrawQuotaTotal = ""
+
+
+
+ def print_object(self, format_data=""):
+ from huobi.utils.print_mix_object import PrintBasic
+ PrintBasic.print_basic(self.chain, format_data + "Chain")
+ PrintBasic.print_basic(self.maxWithdrawAmt, format_data + "maxWithdrawAmt")
+ PrintBasic.print_basic(self.withdrawQuotaPerDay, format_data + "withdrawQuotaPerDay")
+ PrintBasic.print_basic(self.remainWithdrawQuotaPerDay, format_data + "remainWithdrawQuotaPerDay")
+ PrintBasic.print_basic(self.withdrawQuotaPerYear, format_data + "withdrawQuotaPerYear")
+ PrintBasic.print_basic(self.remainWithdrawQuotaPerYear, format_data + "remainWithdrawQuotaPerYear")
+ PrintBasic.print_basic(self.withdrawQuotaTotal, format_data + "withdrawQuotaTotal")
+ PrintBasic.print_basic(self.remainWithdrawQuotaTotal, format_data + "remainWithdrawQuotaTotal")
diff --git a/huobi/service/__init__.py b/huobi/service/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/service/account/__init__.py b/huobi/service/account/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/service/account/error_code.md b/huobi/service/account/error_code.md
new file mode 100644
index 0000000..99e4095
--- /dev/null
+++ b/huobi/service/account/error_code.md
@@ -0,0 +1,13 @@
+常见错误码
+以下是账户相关接口返回的错误码、错误消息以及说明。
+
+错误码 错误消息 说明
+500 system error 调用内部服务异常
+1002 forbidden 禁止操作,如用户入参中accountId与UID不一致
+2002 "invalid field value in currency" currency不符合正则规则^[a-z0-9]{2,10}$
+2002 "invalid field value in transactTypes" 变动类型transactTypes不是“transfer”
+2002 "invalid field value in sort" 分页请求参数不是合法的"asc或desc"
+2002 "value in fromId is not found in record” 未找到fromId
+2002 "invalid field value in accountId" 查询参数中accountId为空
+2002 "value in startTime exceeded valid range" 入参查询时间大于当前时间,或者距离当前时间超过180天
+2002 "value in endTime exceeded valid range") 查询结束时间小于开始时间,或者查询时间跨度大于10天
\ No newline at end of file
diff --git a/huobi/service/account/get_account_asset_valuation.py b/huobi/service/account/get_account_asset_valuation.py
new file mode 100644
index 0000000..6162c27
--- /dev/null
+++ b/huobi/service/account/get_account_asset_valuation.py
@@ -0,0 +1,38 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account.account_asset_valuation import AccountAssetValuationResult
+from huobi.utils import *
+'''
+获取账户资产估值
+API Key 权限:读取
+
+限频值(NEW):100次/2s
+
+按照BTC或法币计价单位,获取指定账户的总资产估值。
+请求参数:
+accountType 账户类型 spot:现货账户, margin:逐仓杠杆账户,otc:OTC 账户,super-margin:全仓杠杆账户
+valuationCurrency 资产估值法币,即资产按哪个法币为单位进行估值。 可选法币有:BTC、CNY、USD、JPY、KRW、GBP、TRY、EUR、RUB、VND、HKD、TWD、MYR、SGD、AED、SAR (大小写敏感)
+subUid 子用户的 UID,若不填,则返回API key所属用户的账户资产估值
+{
+ "code": 200,
+ "data": {
+ "balance": "34.75", 按照某一个法币为单位的总资产估值
+ "timestamp": 1594901254363 数据返回时间,为unix time in millisecond
+ },
+ "ok": true
+}
+'''
+
+class GetAccountAssetValuationService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/account/asset-valuation"
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ return default_parse(data, AccountAssetValuationResult, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
diff --git a/huobi/service/account/get_account_balance_by_subuid.py b/huobi/service/account/get_account_balance_by_subuid.py
new file mode 100644
index 0000000..2953207
--- /dev/null
+++ b/huobi/service/account/get_account_balance_by_subuid.py
@@ -0,0 +1,22 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account import *
+
+
+class GetAccountBalanceBySubUidService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ sub_uid = self.params["sub-uid"]
+
+ def get_channel():
+ path = "/v1/account/accounts/{}"
+ return path.format(sub_uid)
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return AccountBalance.json_parse_list(data_list)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, get_channel(), self.params, parse)
diff --git a/huobi/service/account/get_account_history.py b/huobi/service/account/get_account_history.py
new file mode 100644
index 0000000..213c39e
--- /dev/null
+++ b/huobi/service/account/get_account_history.py
@@ -0,0 +1,30 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account import *
+from huobi.utils import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#0d3c2e7382
+账户流水
+API Key 权限:读取
+限频值(NEW):5次/2s
+
+该节点基于用户账户ID返回账户流水。
+
+'''
+
+class GetAccountHistoryService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/account/history"
+
+ def parse(dict_data):
+ response = dict()
+ data_list = dict_data.get("data", [])
+ response['data'] = default_parse_list_dict(data_list, AccountHistory, [])
+ response['next_id'] = dict_data.get("next-id", 0)
+ return response
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
diff --git a/huobi/service/account/get_account_ledger.py b/huobi/service/account/get_account_ledger.py
new file mode 100644
index 0000000..2802131
--- /dev/null
+++ b/huobi/service/account/get_account_ledger.py
@@ -0,0 +1,36 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account import *
+from huobi.utils import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#84f1b5486d
+财务流水
+API Key 权限:读取
+
+该节点基于用户账户ID返回财务流水。
+一期上线暂时仅支持划转流水的查询(“transactType” = “transfer”)。
+通过“startTime”/“endTime”框定的查询窗口最大为10天,意即,通过单次查询可检索的范围最大为10天。
+该查询窗口可在最近180天范围内平移,意即,通过多次平移窗口查询,最多可检索到过往180天的记录。
+
+'''
+
+
+class GetAccountLedgerService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/account/ledger"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, AccountLedger, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/account/get_account_point.py b/huobi/service/account/get_account_point.py
new file mode 100644
index 0000000..b2d03ad
--- /dev/null
+++ b/huobi/service/account/get_account_point.py
@@ -0,0 +1,19 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account import *
+from huobi.utils import *
+
+
+class GetAccountPointService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/point/account"
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ return default_parse(data, AccountPointResult, {})
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
diff --git a/huobi/service/account/get_accounts.py b/huobi/service/account/get_accounts.py
new file mode 100644
index 0000000..51572a2
--- /dev/null
+++ b/huobi/service/account/get_accounts.py
@@ -0,0 +1,50 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account import *
+from huobi.utils import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#555911a809
+账户信息
+API Key 权限:读取
+限频值(NEW):100次/2s
+响应数据
+
+
+{
+ "data": [
+ {
+ "id": 100001, account-id
+ "type": "spot", 账户类型 spot:现货账户, margin:逐仓杠杆账户, otc:OTC 账户, point:点卡账户, super-margin:全仓杠杆账户, investment: C2C杠杆借出账户, borrow: C2C杠杆借入账户,矿池账户: minepool, ETF账户: etf, 抵押借贷账户: crypto-loans
+ "subtype": "", 子账户类型(仅对逐仓杠杆账户有效) 逐仓杠杆交易标的,例如btcusdt
+ "state": "working" 账户状态 working:正常, lock:账户被锁定
+ }
+ {
+ "id": 100002,
+ "type": "margin",
+ "subtype": "btcusdt",
+ "state": "working"
+ },
+ {
+ "id": 100003,
+ "type": "otc",
+ "subtype": "",
+ "state": "working"
+ }
+ ]
+}
+逐仓/全仓/C2C杠杆账户(margin/super-margin/borrow)会在第一次划转资产时创建,如果未划转过资产则不会有杠杆账户。
+'''
+
+class GetAccountsService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/account/accounts"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, Account, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
diff --git a/huobi/service/account/get_aggregate_subuser_balance.py b/huobi/service/account/get_aggregate_subuser_balance.py
new file mode 100644
index 0000000..c8610e2
--- /dev/null
+++ b/huobi/service/account/get_aggregate_subuser_balance.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account import *
+from huobi.utils import *
+
+
+
+class GetAggregateSubUserBalanceService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/subuser/aggregate-balance"
+
+ def parse(dict_data):
+ data = dict_data.get("data", [])
+ return default_parse_list_dict(data, Balance)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/account/get_balance.py b/huobi/service/account/get_balance.py
new file mode 100644
index 0000000..f4f2678
--- /dev/null
+++ b/huobi/service/account/get_balance.py
@@ -0,0 +1,66 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account import *
+from huobi.utils import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#bd9157656f
+账户余额
+API Key 权限:读取
+限频值(NEW):100次/2s
+查询指定账户的余额,支持以下账户:
+
+spot:现货账户, margin:逐仓杠杆账户,otc:OTC 账户,point:点卡账户,super-margin:全仓杠杆账户, investment: C2C杠杆借出账户, borrow: C2C杠杆借入账户
+响应数据
+{
+ "data": {
+ "id": 100009, 账户 ID
+ "type": "spot", 账户类型 pot:现货账户, margin:逐仓杠杆账户, otc:OTC 账户, point:点卡账户, super-margin:全仓杠杆账户, investment: C2C杠杆借出账户, borrow: C2C杠杆借入账户,矿池账户: minepool, ETF账户: etf, 抵押借贷账户: crypto-loans
+ "state": "working", 账户状态 working:正常 lock:账户被锁定
+ "list": [
+ {
+ "currency": "usdt", 币种
+ "type": "trade", 类型 trade: 交易余额,frozen: 冻结余额, loan: 待还借贷本金, interest: 待还借贷利息, lock: 锁仓, bank: 储蓄
+ "balance": "5007.4362872650" 余额
+ },
+ {
+ "currency": "usdt",
+ "type": "frozen",
+ "balance": "348.1199920000"
+ }
+ ]
+ }
+}
+'''
+
+class GetBalanceService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ account_id = self.params["account-id"]
+
+ def get_channel():
+ path = "/v1/account/accounts/{}/balance"
+ return path.format(account_id)
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ balance_list = data.get("list", [])
+ return default_parse_list_dict(balance_list, Balance, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, get_channel(), self.params, parse)
+
+ def get_request(self, **kwargs):
+ account_id = self.params["account-id"]
+
+ def get_channel():
+ path = "/v1/account/accounts/{}/balance"
+ return path.format(account_id)
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ balance_list = data.get("list", [])
+ return default_parse_list_dict(balance_list, Balance, [])
+
+ return RestApiSyncClient(**kwargs).create_request(HttpMethod.GET_SIGN, get_channel(), self.params, parse)
diff --git a/huobi/service/account/post_account_transfer.py b/huobi/service/account/post_account_transfer.py
new file mode 100644
index 0000000..b5d31f7
--- /dev/null
+++ b/huobi/service/account/post_account_transfer.py
@@ -0,0 +1,41 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account import *
+from huobi.utils import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#c5034eb6d0
+资产划转
+API Key 权限:交易
+
+该节点为母用户和子用户进行资产划转的通用接口。
+
+母用户和子用户均支持的功能包括:
+1、币币账户与逐仓杠杠账户之间的划转;
+2、逐仓杠杠不同账户间相同币种的直接划转,如逐仓杠杠BTC/USDT账户和ETH/USDT账户,相同币种USDT可直接划转;
+
+仅母用户支持的功能包括:
+1、母用户币币账户与子用户币币账户间的划转;
+2、不同子用户币币账户间划转;
+
+仅子用户支持的功能包括:
+1、子用户币币账户向母用户下的其他子用户币币账户划转,此权限默认关闭,需母用户授权。授权接口为 POST /v2/sub-user/transferability;
+2、子用户币币账户向母用户币币账户划转;
+
+其他划转功能将逐步上线,敬请期待。
+
+
+'''
+
+class PostAccountTransferService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/account/transfer"
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ return default_parse(data, AccountTransferResult, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/account/post_futures_and_pro_transfer.py b/huobi/service/account/post_futures_and_pro_transfer.py
new file mode 100644
index 0000000..802af81
--- /dev/null
+++ b/huobi/service/account/post_futures_and_pro_transfer.py
@@ -0,0 +1,23 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostTransferBetweenFuturesAndProService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/futures/transfer"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/account/post_point_transfer.py b/huobi/service/account/post_point_transfer.py
new file mode 100644
index 0000000..b771c3c
--- /dev/null
+++ b/huobi/service/account/post_point_transfer.py
@@ -0,0 +1,19 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account import *
+from huobi.utils import *
+
+
+class PostPointTransferService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/point/transfer"
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ return default_parse(data, AccountPointTransferResult, {})
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/account/post_sub_uid_management.py b/huobi/service/account/post_sub_uid_management.py
new file mode 100644
index 0000000..226f300
--- /dev/null
+++ b/huobi/service/account/post_sub_uid_management.py
@@ -0,0 +1,24 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils import *
+from huobi.model.account import *
+
+
+class PostSubUidManagementService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/sub-user/management"
+
+ def parse(dict_data):
+ return default_parse_list_dict(dict_data.get("data", {}), SubUidManagement)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/account/post_subaccount_transfer.py b/huobi/service/account/post_subaccount_transfer.py
new file mode 100644
index 0000000..832b844
--- /dev/null
+++ b/huobi/service/account/post_subaccount_transfer.py
@@ -0,0 +1,24 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostSubaccountTransferService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/subuser/transfer"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/account/req_account_balance.py b/huobi/service/account/req_account_balance.py
new file mode 100644
index 0000000..7226b36
--- /dev/null
+++ b/huobi/service/account/req_account_balance.py
@@ -0,0 +1,34 @@
+
+from huobi.utils import *
+
+from huobi.connection.websocket_req_client import *
+from huobi.model.account import *
+
+
+
+class ReqAccountBalanceService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ client_req_id = self.params["client_req_id"]
+ def subscription(connection):
+ connection.send(request_account_list_channel(client_req_id))
+
+ def parse(dict_data):
+ req_obj = AccountBalanceReq()
+ req_obj.ts = dict_data.get("ts", 0)
+ req_obj.topic = dict_data.get("topic", 0)
+ req_obj.cid = dict_data.get("cid", 0)
+ data_list = dict_data.get("data", [])
+ req_obj.data = AccountBalance.json_parse_list(data_list)
+ return req_obj
+
+ WebSocketReqClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler,
+ is_trade=True)
+
+
+
diff --git a/huobi/service/account/sub_account_update_v2.py b/huobi/service/account/sub_account_update_v2.py
new file mode 100644
index 0000000..a1e1b3f
--- /dev/null
+++ b/huobi/service/account/sub_account_update_v2.py
@@ -0,0 +1,30 @@
+from huobi.utils import *
+
+from huobi.connection.subscribe_client import SubscribeClient
+from huobi.model.account import *
+
+
+class SubAccountUpdateV2Service:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ mode = self.params["mode"]
+
+ def subscription(connection):
+ connection.send(accounts_update_channel(mode))
+
+ def parse(dict_data):
+ account_change_event = AccountUpdateEvent()
+ account_change_event.ch = dict_data.get("ch")
+ data = dict_data.get("data", {})
+ if data and len(data):
+ account_change_event.data = default_parse_list_dict(data, AccountUpdate)
+
+ return account_change_event
+
+ SubscribeClient(**kwargs).execute_subscribe_v2(subscription,
+ parse,
+ callback,
+ error_handler,
+ is_trade=True)
diff --git a/huobi/service/algo/__init__.py b/huobi/service/algo/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/service/algo/get_open_orders.py b/huobi/service/algo/get_open_orders.py
new file mode 100644
index 0000000..c390037
--- /dev/null
+++ b/huobi/service/algo/get_open_orders.py
@@ -0,0 +1,41 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import *
+from huobi.model.algo import *
+
+
+class GetOpenOrdersService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/algo-orders/opening"
+
+ # {
+ # "code": 200,
+ # "data": [
+ # {
+ # "accountId": 3684354,
+ # "clientOrderId": "test004",
+ # "lastActTime": 1600141535221,
+ # "orderOrigTime": 1600141535137,
+ # "orderPrice": "0.08",
+ # "orderSide": "buy",
+ # "orderSize": "65",
+ # "orderStatus": "created",
+ # "orderType": "limit",
+ # "source": "api",
+ # "stopPrice": "0.085",
+ # "symbol": "adausdt",
+ # "trailingRate": 0.001,
+ # "timeInForce": "gtc"
+ # }
+ # ]
+ # }
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ return default_parse_list_dict(data, OrderListItem)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
diff --git a/huobi/service/algo/get_order_by_cid.py b/huobi/service/algo/get_order_by_cid.py
new file mode 100644
index 0000000..c33c285
--- /dev/null
+++ b/huobi/service/algo/get_order_by_cid.py
@@ -0,0 +1,19 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import *
+from huobi.model.algo import *
+
+
+class GetOrderByClientOrderIdService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/algo-orders/specific"
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ return default_parse(data, OrderHistoryItem)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
diff --git a/huobi/service/algo/get_order_history.py b/huobi/service/algo/get_order_history.py
new file mode 100644
index 0000000..05aee58
--- /dev/null
+++ b/huobi/service/algo/get_order_history.py
@@ -0,0 +1,19 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import *
+from huobi.model.algo import *
+
+
+class GetOrderHistoryService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/algo-orders/history"
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ return default_parse_list_dict(data, OrderHistoryItem)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
diff --git a/huobi/service/algo/post_cancel_orders.py b/huobi/service/algo/post_cancel_orders.py
new file mode 100644
index 0000000..96caaff
--- /dev/null
+++ b/huobi/service/algo/post_cancel_orders.py
@@ -0,0 +1,20 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import default_parse_fill_directly
+from huobi.model.algo import *
+
+
+class PostCancelOrderService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/algo-orders/cancellation"
+
+ # {'code': 200, 'data': {'accepted': [], 'rejected': ['test001', 'test002']}}
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ return default_parse_fill_directly(data, CancelOrderResult)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/algo/post_create_order.py b/huobi/service/algo/post_create_order.py
new file mode 100644
index 0000000..9f3ab86
--- /dev/null
+++ b/huobi/service/algo/post_create_order.py
@@ -0,0 +1,18 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+
+
+class PostCreateOrderService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/algo-orders"
+
+ # {'code': 200, 'data': {'clientOrderId': 'test001'}}
+ def parse(dict_data):
+ data = dict_data.get('data')
+ return data.get('clientOrderId')
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/etf/__init__.py b/huobi/service/etf/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/service/etf/get_etf_swap_config.py b/huobi/service/etf/get_etf_swap_config.py
new file mode 100644
index 0000000..9712b9d
--- /dev/null
+++ b/huobi/service/etf/get_etf_swap_config.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.etf import *
+from huobi.utils import *
+
+
+
+class GetEtfSwapConfigService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/etf/swap/config"
+
+ def parse(dict_data):
+ data_info = dict_data.get("data", {})
+ return default_parse(data_info, EtfSwapConfig, UnitPrice)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/etf/get_etf_swap_list.py b/huobi/service/etf/get_etf_swap_list.py
new file mode 100644
index 0000000..26d01dd
--- /dev/null
+++ b/huobi/service/etf/get_etf_swap_list.py
@@ -0,0 +1,23 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.etf import *
+
+class GetEtfSwapListService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/etf/swap/list"
+
+ def parse(dict_data):
+ return EtfSwapList.json_parse_list(dict_data.get("data", []))
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
+
diff --git a/huobi/service/etf/post_etf_swap_in.py b/huobi/service/etf/post_etf_swap_in.py
new file mode 100644
index 0000000..f7b28eb
--- /dev/null
+++ b/huobi/service/etf/post_etf_swap_in.py
@@ -0,0 +1,28 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils import *
+from huobi.model.etf import *
+
+
+
+class PostEftSwapInService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/etf/swap/in"
+
+ def parse(dict_data):
+ return default_parse_fill_directly(dict_data, EtfSwapInOut)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
+
+
+
diff --git a/huobi/service/etf/post_etf_swap_out.py b/huobi/service/etf/post_etf_swap_out.py
new file mode 100644
index 0000000..9eca017
--- /dev/null
+++ b/huobi/service/etf/post_etf_swap_out.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils import *
+from huobi.model.etf import *
+
+
+class PostEtfSwapOutService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/etf/swap/out"
+
+ def parse(dict_data):
+ return default_parse_fill_directly(dict_data, EtfSwapInOut)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
+
diff --git a/huobi/service/generic/__init__.py b/huobi/service/generic/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/service/generic/get_exchange_currencies.py b/huobi/service/generic/get_exchange_currencies.py
new file mode 100644
index 0000000..d403c34
--- /dev/null
+++ b/huobi/service/generic/get_exchange_currencies.py
@@ -0,0 +1,23 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+
+
+class GetExchangeCurrenciesService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/common/currencys"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return data_list if len(data_list) else []
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/generic/get_exchange_symbols.py b/huobi/service/generic/get_exchange_symbols.py
new file mode 100644
index 0000000..b92a56e
--- /dev/null
+++ b/huobi/service/generic/get_exchange_symbols.py
@@ -0,0 +1,19 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.generic import *
+from huobi.utils import *
+
+
+class GetExchangeSymbolsService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/common/symbols"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, Symbol, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
diff --git a/huobi/service/generic/get_exchange_timestamp.py b/huobi/service/generic/get_exchange_timestamp.py
new file mode 100644
index 0000000..f95d669
--- /dev/null
+++ b/huobi/service/generic/get_exchange_timestamp.py
@@ -0,0 +1,24 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils import *
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class GetExchangeTimestampService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/common/timestamp"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/generic/get_market_status.py b/huobi/service/generic/get_market_status.py
new file mode 100644
index 0000000..788e55c
--- /dev/null
+++ b/huobi/service/generic/get_market_status.py
@@ -0,0 +1,18 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.generic import *
+from huobi.utils import *
+
+
+class GetMarketStatusService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/market-status"
+
+ def parse(dict_data):
+ return default_parse(dict_data.get("data", {}), MarketStatus)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
diff --git a/huobi/service/generic/get_reference_currencies.py b/huobi/service/generic/get_reference_currencies.py
new file mode 100644
index 0000000..cda6039
--- /dev/null
+++ b/huobi/service/generic/get_reference_currencies.py
@@ -0,0 +1,31 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.generic import *
+from huobi.utils import *
+
+
+
+class GetReferenceCurrenciesService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/reference/currencies"
+
+ def parse(dict_data):
+ ret_list = []
+ data_list = dict_data.get("data", [])
+ if data_list and len(data_list):
+ for reference_currency in data_list:
+ reference_currency_obj = default_parse(reference_currency, ReferenceCurrency, Chain)
+ ret_list.append(reference_currency_obj)
+ return ret_list
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/generic/get_system_status.py b/huobi/service/generic/get_system_status.py
new file mode 100644
index 0000000..ebeffa5
--- /dev/null
+++ b/huobi/service/generic/get_system_status.py
@@ -0,0 +1,23 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+
+
+class GetSystemStatusService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/api/v2/summary.json"
+ kwargs["url"] = "https://status.huobigroup.com"
+
+ def parse(dict_data):
+ return dict_data
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/linear-swap/__init__.py b/huobi/service/linear-swap/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/service/linear-swap/post_swap_openorders.py b/huobi/service/linear-swap/post_swap_openorders.py
new file mode 100644
index 0000000..b8249fe
--- /dev/null
+++ b/huobi/service/linear-swap/post_swap_openorders.py
@@ -0,0 +1,69 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+
+'''
+https://huobiapi.github.io/docs/usdt_swap/v1/cn/#136259e73a
+该接口仅支持逐仓模式。
+请求参数
+参数名称 是否必须 类型 描述 取值范围
+contract_code true string 合约代码 "BTC-USDT" ...
+page_index false int 页码,不填默认第1页
+page_size false int 页长,不填默认20,不得多于50
+
+返回参数
+参数名称 是否必须 类型 描述 取值范围
+status true string 请求处理结果
+
+
+symbol true string 品种代码
+contract_code true string 合约代码 "BTC-USDT" ...
+volume true decimal 委托数量
+price true decimal 委托价格
+order_price_type true string 订单报价类型 "limit":限价,"opponent":对手价,"post_only":只做maker单,post only下单只受用户持仓数量限制,"lightning":闪电平仓,"optimal_5":最优5档,"optimal_10":最优10档,"optimal_20":最优20档,"fok":FOK订单,"ioc":IOC订单, "opponent_ioc": 对手价-IOC下单,"lightning_ioc": 闪电平仓-IOC下单,"optimal_5_ioc": 最优5档-IOC下单,"optimal_10_ioc": 最优10档-IOC下单,"optimal_20_ioc":最优20档-IOC下单,"opponent_fok": 对手价-FOK下单,"lightning_fok":闪电平仓-FOK下单,"optimal_5_fok":最优5档-FOK下单,"optimal_10_fok":最优10档-FOK下单,"optimal_20_fok":最优20档-FOK下单
+order_type true int 订单类型 1:报单 、 2:撤单 、 3:强平、4:交割
+direction true string "buy":买 "sell":卖
+offset true string "open":开 "close":平
+lever_rate true int 杠杆倍数
+order_id true long 订单ID
+order_id_str true string 订单ID,字符串类型
+client_order_id true long 客户订单ID
+created_at true long 订单创建时间
+trade_volume true decimal 成交数量
+trade_turnover true decimal 成交总金额
+fee true decimal 手续费
+fee_asset true string 手续费币种 "BTC","ETH"...
+trade_avg_price true decimal 成交均价
+margin_frozen true decimal 冻结保证金
+margin_asset true string 保证金币种(计价币种)
+profit true decimal 收益
+status true int 订单状态 (3未成交 4部分成交 5部分成交已撤单 6全部成交 7已撤单)
+order_source true string 订单来源 (system:系统、web:用户网页、api:用户API、m:用户M站、risk:风控系统、settlement:交割结算、ios:ios客户端、android:安卓客户端、windows:windows客户端、mac:mac客户端、trigger:计划委托触发、tpsl:止盈止损触发)
+liquidation_type true string 强平类型
+canceled_at true long 撤单时间
+margin_mode true string 保证金模式 isolated:逐仓模式
+margin_account true string 保证金账户 比如“BTC-USDT”
+is_tpsl true int 是否设置止盈止损 1:是;0:否
+
+total_page true int 总页数
+current_page true int 当前页
+total_size true int 总条数
+
+ts true long 时间戳
+'''
+
+
+class PostSwapOpenOrdersService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/linear-swap-api/v1/swap_openorders"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/margin/__init__.py b/huobi/service/margin/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/service/margin/get_cross_margin_account_balance.py b/huobi/service/margin/get_cross_margin_account_balance.py
new file mode 100644
index 0000000..b534211
--- /dev/null
+++ b/huobi/service/margin/get_cross_margin_account_balance.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.margin import *
+from huobi.utils import *
+
+
+
+class GetCrossMarginAccountBalanceService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/cross-margin/accounts/balance"
+
+ def parse(dict_data):
+ return CrossMarginAccountBalance.json_parse(dict_data.get("data", {}))
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/get_cross_margin_loan_info.py b/huobi/service/margin/get_cross_margin_loan_info.py
new file mode 100644
index 0000000..30040d2
--- /dev/null
+++ b/huobi/service/margin/get_cross_margin_loan_info.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.margin import *
+from huobi.utils import *
+
+
+
+class GetCrossMarginLoanInfoService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/cross-margin/loan-info"
+
+ def parse(dict_data):
+ return default_parse_list_dict(dict_data.get("data", []), CrossMarginLoanInfo, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/get_cross_margin_loan_orders.py b/huobi/service/margin/get_cross_margin_loan_orders.py
new file mode 100644
index 0000000..36c8878
--- /dev/null
+++ b/huobi/service/margin/get_cross_margin_loan_orders.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.margin import *
+from huobi.utils import *
+
+
+
+class GetCrossMarginLoanOrdersService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/cross-margin/loan-orders"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, LoanOrder, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/get_general_repayment_loan_records.py b/huobi/service/margin/get_general_repayment_loan_records.py
new file mode 100644
index 0000000..59df420
--- /dev/null
+++ b/huobi/service/margin/get_general_repayment_loan_records.py
@@ -0,0 +1,22 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.margin.general_repay_loan_record import GeneralRepayLoanRecord
+from huobi.model.margin.general_repay_loan_result import GeneralRepayLoanResult
+from huobi.utils.json_parser import default_parse_list_dict
+
+
+class GetGeneralRepaymentLoanRecordsService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+
+ def get_channel():
+ path = "/v2/account/repayment"
+ return path
+
+ def parse(dict_data):
+ return default_parse_list_dict(dict_data.get("data", {}), GeneralRepayLoanRecord)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, get_channel(), self.params, parse)
\ No newline at end of file
diff --git a/huobi/service/margin/get_margin_account_balance.py b/huobi/service/margin/get_margin_account_balance.py
new file mode 100644
index 0000000..14531a6
--- /dev/null
+++ b/huobi/service/margin/get_margin_account_balance.py
@@ -0,0 +1,32 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.account import Balance
+from huobi.model.margin import *
+from huobi.utils import *
+
+
+
+class GetMarginAccountBalanceService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/margin/accounts/balance"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ account_balance_list = []
+ if data_list and len(data_list):
+ for row in data_list:
+ account_balance = default_parse(row, MarginAccountBalance, Balance)
+ account_balance_list.append(account_balance)
+ return account_balance_list
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/get_margin_loan_info.py b/huobi/service/margin/get_margin_loan_info.py
new file mode 100644
index 0000000..82b9a04
--- /dev/null
+++ b/huobi/service/margin/get_margin_loan_info.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.margin import *
+from huobi.utils import *
+
+
+
+class GetMarginLoanInfoService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/margin/loan-info"
+
+ def parse(dict_data):
+ return MarginLoanInfo.json_parse(dict_data.get("data", []))
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/get_margin_loan_orders.py b/huobi/service/margin/get_margin_loan_orders.py
new file mode 100644
index 0000000..509d210
--- /dev/null
+++ b/huobi/service/margin/get_margin_loan_orders.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.margin import *
+from huobi.utils import *
+
+
+
+class GetMarginLoanOrdersService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/margin/loan-orders"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, LoanOrder, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/post_create_margin_order.py b/huobi/service/margin/post_create_margin_order.py
new file mode 100644
index 0000000..1ffc452
--- /dev/null
+++ b/huobi/service/margin/post_create_margin_order.py
@@ -0,0 +1,23 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostCreateMarginOrderService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/margin/orders"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/post_cross_margin_create_loan_orders.py b/huobi/service/margin/post_cross_margin_create_loan_orders.py
new file mode 100644
index 0000000..f99fa3e
--- /dev/null
+++ b/huobi/service/margin/post_cross_margin_create_loan_orders.py
@@ -0,0 +1,23 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostCrossMarginCreateLoanOrdersService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/cross-margin/orders"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/post_cross_margin_loan_order_repay.py b/huobi/service/margin/post_cross_margin_loan_order_repay.py
new file mode 100644
index 0000000..0fc53eb
--- /dev/null
+++ b/huobi/service/margin/post_cross_margin_loan_order_repay.py
@@ -0,0 +1,22 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+
+
+class PostCrossMarginLoanOrderRepayService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/cross-margin/orders/{order_id}/repay".format(order_id=self.params.get("order-id"))
+
+ def parse(dict_data):
+ return dict_data.get("status", None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/post_cross_margin_transfer_in.py b/huobi/service/margin/post_cross_margin_transfer_in.py
new file mode 100644
index 0000000..dada255
--- /dev/null
+++ b/huobi/service/margin/post_cross_margin_transfer_in.py
@@ -0,0 +1,24 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostCrossMarginTransferInService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/cross-margin/transfer-in"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/post_cross_margin_transfer_out.py b/huobi/service/margin/post_cross_margin_transfer_out.py
new file mode 100644
index 0000000..91f7019
--- /dev/null
+++ b/huobi/service/margin/post_cross_margin_transfer_out.py
@@ -0,0 +1,24 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostCrossMarginTransferOutService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/cross-margin/transfer-out"
+
+ def parse(dict_data):
+ transfer_id = default_parse_data_as_long(dict_data, None)
+ return transfer_id
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/post_general_repay_loan.py b/huobi/service/margin/post_general_repay_loan.py
new file mode 100644
index 0000000..95d26dc
--- /dev/null
+++ b/huobi/service/margin/post_general_repay_loan.py
@@ -0,0 +1,21 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.margin.general_repay_loan_result import GeneralRepayLoanResult
+from huobi.utils.json_parser import default_parse_list_dict
+
+
+class PostGeneralRepayLoanService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+
+ def get_channel():
+ path = "/v2/account/repayment"
+ return path
+
+ def parse(dict_data):
+ return default_parse_list_dict(dict_data.get("data", {}), GeneralRepayLoanResult)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, get_channel(), self.params, parse)
\ No newline at end of file
diff --git a/huobi/service/margin/post_repay_margin_order.py b/huobi/service/margin/post_repay_margin_order.py
new file mode 100644
index 0000000..d1f7a53
--- /dev/null
+++ b/huobi/service/margin/post_repay_margin_order.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostRepayMarginOrderService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ loan_id = self.params["loan_id"]
+ def get_channel():
+ path = "/v1/margin/orders/{}/repay"
+ return path.format(loan_id)
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, get_channel(), self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/post_transfer_in_margin.py b/huobi/service/margin/post_transfer_in_margin.py
new file mode 100644
index 0000000..3415432
--- /dev/null
+++ b/huobi/service/margin/post_transfer_in_margin.py
@@ -0,0 +1,23 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostTransferInMarginService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/dw/transfer-in/margin"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/margin/post_transfer_out_margin.py b/huobi/service/margin/post_transfer_out_margin.py
new file mode 100644
index 0000000..57e4876
--- /dev/null
+++ b/huobi/service/margin/post_transfer_out_margin.py
@@ -0,0 +1,23 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostTransferOutMarginService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/dw/transfer-out/margin"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/market/__init__.py b/huobi/service/market/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/huobi/service/market/__init__.py
@@ -0,0 +1 @@
+
diff --git a/huobi/service/market/get_candlestick.py b/huobi/service/market/get_candlestick.py
new file mode 100644
index 0000000..6fa76ee
--- /dev/null
+++ b/huobi/service/market/get_candlestick.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.market import *
+from huobi.utils import *
+
+
+
+class GetCandleStickService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/market/history/kline"
+
+ def parse(dict_data):
+ return default_parse_list_dict(dict_data.get("data", []), Candlestick)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/market/get_history_trade.py b/huobi/service/market/get_history_trade.py
new file mode 100644
index 0000000..8e9015d
--- /dev/null
+++ b/huobi/service/market/get_history_trade.py
@@ -0,0 +1,35 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.market import *
+from huobi.utils import *
+
+
+class GetHistoryTradeService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/market/history/trade"
+
+ def parse(dict_data):
+ trade_list_ret = [] # two level list, list item is list too
+ data_list_outer = dict_data.get("data", [])
+ if len(data_list_outer):
+ for row in data_list_outer:
+ data_list_inner = row.get("data", [])
+ if len(data_list_inner):
+ for trade_info in data_list_inner:
+ trade_obj = default_parse_list_dict(trade_info, Trade, None) # return a list
+ if trade_obj:
+ trade_list_ret.append(trade_obj)
+
+ return trade_list_ret
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/market/get_market_detail.py b/huobi/service/market/get_market_detail.py
new file mode 100644
index 0000000..8b72e20
--- /dev/null
+++ b/huobi/service/market/get_market_detail.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.market import *
+from huobi.utils import *
+
+
+
+class GetMarketDetailService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/market/detail"
+
+ def parse(dict_data):
+ tick = dict_data.get("tick", {})
+ return default_parse(tick, MarketDetail)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/market/get_market_detail_merged.py b/huobi/service/market/get_market_detail_merged.py
new file mode 100644
index 0000000..94977c0
--- /dev/null
+++ b/huobi/service/market/get_market_detail_merged.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.market import *
+from huobi.utils import *
+
+
+
+class GetMarketDetailMergedService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/market/detail/merged"
+
+ def parse(dict_data):
+ tick = dict_data.get("tick", {})
+ return default_parse_fill_directly(tick, MarketDetailMerged)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/market/get_market_tickers.py b/huobi/service/market/get_market_tickers.py
new file mode 100644
index 0000000..285c343
--- /dev/null
+++ b/huobi/service/market/get_market_tickers.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.market import *
+from huobi.utils import *
+
+
+
+class GetMarketTickersService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/market/tickers"
+
+ def parse(dict_data):
+ return default_parse_list_dict(dict_data.get("data", []), MarketTicker)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/market/get_market_trade.py b/huobi/service/market/get_market_trade.py
new file mode 100644
index 0000000..9d14e06
--- /dev/null
+++ b/huobi/service/market/get_market_trade.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.market import *
+from huobi.utils import *
+
+
+class GetMarketTradeService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/market/trade"
+
+ def parse(dict_data):
+ tick = dict_data.get("tick", {})
+ data = tick.get("data", [])
+ return default_parse_list_dict(data, Trade, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/market/get_pricedepth.py b/huobi/service/market/get_pricedepth.py
new file mode 100644
index 0000000..a245382
--- /dev/null
+++ b/huobi/service/market/get_pricedepth.py
@@ -0,0 +1,24 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.market import PriceDepth
+
+
+class GetPriceDepthService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/market/depth"
+
+ def parse(dict_data):
+ tick = dict_data.get("tick", {})
+ return PriceDepth.json_parse(tick)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/market/req_candlestick.py b/huobi/service/market/req_candlestick.py
new file mode 100644
index 0000000..695a039
--- /dev/null
+++ b/huobi/service/market/req_candlestick.py
@@ -0,0 +1,34 @@
+import time
+
+from huobi.utils import *
+
+from huobi.connection.websocket_req_client import *
+from huobi.model.market import *
+from huobi.utils.channels_request import *
+
+
+class ReqCandleStickService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+ interval = self.params["interval"]
+ from_ts_second = self.params.get("from_ts_second", None)
+ end_ts_second = self.params.get("end_ts_second", None)
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(request_kline_channel(symbol, interval, from_ts_second, end_ts_second))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return default_parse(dict_data, CandlestickReq, Candlestick)
+
+ WebSocketReqClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler)
+
+
+
diff --git a/huobi/service/market/req_market_detail.py b/huobi/service/market/req_market_detail.py
new file mode 100644
index 0000000..043b204
--- /dev/null
+++ b/huobi/service/market/req_market_detail.py
@@ -0,0 +1,31 @@
+import time
+
+from huobi.utils import *
+
+from huobi.connection.websocket_req_client import *
+from huobi.model.market import *
+from huobi.utils.channels_request import *
+
+
+class ReqMarketDetailService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(request_market_detail_channel(symbol))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return default_parse(dict_data, MarketDetailReq, MarketDetail)
+
+ WebSocketReqClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler)
+
+
+
diff --git a/huobi/service/market/req_mbp.py b/huobi/service/market/req_mbp.py
new file mode 100644
index 0000000..51aa791
--- /dev/null
+++ b/huobi/service/market/req_mbp.py
@@ -0,0 +1,27 @@
+import time
+
+from huobi.model.market import *
+from huobi.utils import *
+from huobi.connection.websocket_req_client import WebSocketReqClient
+
+
+class ReqMbpService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+ level = self.params["levels"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(request_mbp_channel(symbol, level))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return MbpReq.json_parse(dict_data)
+
+ WebSocketReqClient(**kwargs).execute_subscribe_mbp(subscription,
+ parse,
+ callback,
+ error_handler)
diff --git a/huobi/service/market/req_pricedepth.py b/huobi/service/market/req_pricedepth.py
new file mode 100644
index 0000000..1a5cd59
--- /dev/null
+++ b/huobi/service/market/req_pricedepth.py
@@ -0,0 +1,36 @@
+import time
+
+from huobi.connection.websocket_req_client import *
+from huobi.utils.channels_request import *
+from huobi.model.market import *
+
+
+class ReqPriceDepthService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+ step = self.params["step"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(request_price_depth_channel(symbol, step))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ price_depth_event = PriceDepthReq()
+ price_depth_event.id = dict_data.get("id")
+ price_depth_event.rep = dict_data.get("rep")
+ data = dict_data.get("data", {})
+ price_depth_obj = PriceDepth.json_parse(data)
+ price_depth_event.data = price_depth_obj
+ return price_depth_event
+
+ WebSocketReqClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler)
+
+
+
diff --git a/huobi/service/market/req_trade_detail.py b/huobi/service/market/req_trade_detail.py
new file mode 100644
index 0000000..44b28d4
--- /dev/null
+++ b/huobi/service/market/req_trade_detail.py
@@ -0,0 +1,29 @@
+import time
+
+from huobi.model.market import *
+from huobi.utils import *
+from huobi.connection.websocket_req_client import *
+
+
+class ReqTradeDetailService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(request_trade_detail_channel(symbol))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return default_parse(dict_data, TradeDetailReq, TradeDetail)
+
+ WebSocketReqClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler)
+
+
+
diff --git a/huobi/service/market/sub_candlestick.py b/huobi/service/market/sub_candlestick.py
new file mode 100644
index 0000000..794f87a
--- /dev/null
+++ b/huobi/service/market/sub_candlestick.py
@@ -0,0 +1,33 @@
+import time
+
+from huobi.utils import *
+
+from huobi.connection.subscribe_client import SubscribeClient
+from huobi.model.market import *
+
+
+
+class SubCandleStickService:
+ def __init__(self, params):
+
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+ interval = self.params["interval"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(kline_channel(symbol, interval))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return default_parse(dict_data, CandlestickEvent, Candlestick)
+
+ SubscribeClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler)
+
+
+
diff --git a/huobi/service/market/sub_market_detail.py b/huobi/service/market/sub_market_detail.py
new file mode 100644
index 0000000..13c4655
--- /dev/null
+++ b/huobi/service/market/sub_market_detail.py
@@ -0,0 +1,31 @@
+import time
+
+from huobi.utils import *
+
+from huobi.connection.subscribe_client import SubscribeClient
+from huobi.model.market import *
+
+
+
+class SubMarketDetailService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(market_detail_channel(symbol))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return default_parse(dict_data, MarketDetailEvent, MarketDetail)
+
+ SubscribeClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler)
+
+
+
diff --git a/huobi/service/market/sub_mbp_full.py b/huobi/service/market/sub_mbp_full.py
new file mode 100644
index 0000000..0e99660
--- /dev/null
+++ b/huobi/service/market/sub_mbp_full.py
@@ -0,0 +1,27 @@
+import time
+
+from huobi.model.market import *
+from huobi.utils import *
+from huobi.connection.subscribe_client import SubscribeClient
+
+
+class SubMbpFullService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+ level = self.params["levels"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(mbp_full_channel(symbol, level))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return MbpFullEvent.json_parse(dict_data)
+
+ SubscribeClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler)
diff --git a/huobi/service/market/sub_mbp_increase.py b/huobi/service/market/sub_mbp_increase.py
new file mode 100644
index 0000000..a185769
--- /dev/null
+++ b/huobi/service/market/sub_mbp_increase.py
@@ -0,0 +1,30 @@
+import time
+
+from huobi.model.market import *
+from huobi.utils import *
+from huobi.connection.subscribe_client import SubscribeClient
+
+
+class SubMbpIncreaseService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+ level = self.params["levels"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(mbp_increase_channel(symbol, level))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return MbpIncreaseEvent.json_parse(dict_data)
+
+ SubscribeClient(**kwargs).execute_subscribe_mbp(subscription,
+ parse,
+ callback,
+ error_handler)
+
+
+
diff --git a/huobi/service/market/sub_pricedepth.py b/huobi/service/market/sub_pricedepth.py
new file mode 100644
index 0000000..6210365
--- /dev/null
+++ b/huobi/service/market/sub_pricedepth.py
@@ -0,0 +1,34 @@
+import time
+
+from huobi.model.market import *
+from huobi.utils import *
+from huobi.connection.subscribe_client import SubscribeClient
+
+
+class SubPriceDepthService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+ step = self.params["step"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(price_depth_channel(symbol, step))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ price_depth_event_obj = PriceDepthEvent()
+ price_depth_event_obj.ch = dict_data.get("ch", "")
+ tick = dict_data.get("tick", "")
+ price_depth_event_obj.tick = PriceDepth.json_parse(tick)
+ return price_depth_event_obj
+
+ SubscribeClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler)
+
+
+
diff --git a/huobi/service/market/sub_pricedepth_bbo.py b/huobi/service/market/sub_pricedepth_bbo.py
new file mode 100644
index 0000000..b44597b
--- /dev/null
+++ b/huobi/service/market/sub_pricedepth_bbo.py
@@ -0,0 +1,29 @@
+import time
+
+from huobi.utils import *
+from huobi.model.market import *
+from huobi.connection.subscribe_client import SubscribeClient
+
+
+class SubPriceDepthBboService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(price_depth_bbo_channel(symbol))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return default_parse(dict_data, PriceDepthBboEvent, PriceDepthBbo)
+
+ SubscribeClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler)
+
+
+
diff --git a/huobi/service/market/sub_trade_detail.py b/huobi/service/market/sub_trade_detail.py
new file mode 100644
index 0000000..1bd539b
--- /dev/null
+++ b/huobi/service/market/sub_trade_detail.py
@@ -0,0 +1,32 @@
+import time
+
+from huobi.model.market import *
+from huobi.utils import *
+from huobi.connection.subscribe_client import SubscribeClient
+
+
+class SubTradeDetailService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(trade_detail_channel(symbol))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ tick = dict_data.get("tick", {})
+ trade_detail_event = default_parse(tick, TradeDetailEvent, TradeDetail)
+ trade_detail_event.ch = dict_data.get("ch", "")
+ return trade_detail_event
+
+ SubscribeClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler)
+
+
+
diff --git a/huobi/service/subuser/__init__.py b/huobi/service/subuser/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/service/subuser/get_uid.py b/huobi/service/subuser/get_uid.py
new file mode 100644
index 0000000..1e16c7c
--- /dev/null
+++ b/huobi/service/subuser/get_uid.py
@@ -0,0 +1,20 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils import *
+from huobi.model.subuser import *
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+
+class GetUidService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/user/uid"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
diff --git a/huobi/service/subuser/get_user_apikey_info.py b/huobi/service/subuser/get_user_apikey_info.py
new file mode 100644
index 0000000..a37c392
--- /dev/null
+++ b/huobi/service/subuser/get_user_apikey_info.py
@@ -0,0 +1,18 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils import *
+from huobi.model.subuser import *
+
+
+class GetUserApikeyInfoService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/user/api-key"
+
+ def parse(dict_data):
+ return default_parse_list_dict(dict_data.get("data", {}), UserApikeyInfo)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
diff --git a/huobi/service/subuser/post_create_subuser.py b/huobi/service/subuser/post_create_subuser.py
new file mode 100644
index 0000000..45dd123
--- /dev/null
+++ b/huobi/service/subuser/post_create_subuser.py
@@ -0,0 +1,18 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils import *
+from huobi.model.subuser import *
+
+
+class PostSubuserCreationService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/sub-user/creation"
+
+ def parse(dict_data):
+ return default_parse_list_dict(dict_data.get("data", {}), SubuserCreation)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/subuser/post_set_transferability.py b/huobi/service/subuser/post_set_transferability.py
new file mode 100644
index 0000000..47fe674
--- /dev/null
+++ b/huobi/service/subuser/post_set_transferability.py
@@ -0,0 +1,18 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils import *
+from huobi.model.subuser import *
+
+
+class PostSetSubuserTransferability:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/sub-user/transferability"
+
+ def parse(dict_data):
+ return default_parse_list_dict(dict_data.get("data", {}), SubuserTransferability)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/subuser/post_subuser_apikey_deletion.py b/huobi/service/subuser/post_subuser_apikey_deletion.py
new file mode 100644
index 0000000..821fbfa
--- /dev/null
+++ b/huobi/service/subuser/post_subuser_apikey_deletion.py
@@ -0,0 +1,17 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+
+
+class PostSubuserApikeyDeletionService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/sub-user/api-key-deletion"
+
+ # {'code': 200, 'data': None, 'ok': True}
+ def parse(dict_data):
+ return dict_data
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/subuser/post_subuser_apikey_generation.py b/huobi/service/subuser/post_subuser_apikey_generation.py
new file mode 100644
index 0000000..76243a5
--- /dev/null
+++ b/huobi/service/subuser/post_subuser_apikey_generation.py
@@ -0,0 +1,18 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils import *
+from huobi.model.subuser import *
+
+
+class PostSubuserApikeyGenerationService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/sub-user/api-key-generation"
+
+ def parse(dict_data):
+ return default_parse(dict_data.get("data", {}), SubuserApikeyGeneration)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/subuser/post_subuser_apikey_modification.py b/huobi/service/subuser/post_subuser_apikey_modification.py
new file mode 100644
index 0000000..6671abe
--- /dev/null
+++ b/huobi/service/subuser/post_subuser_apikey_modification.py
@@ -0,0 +1,18 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.utils import *
+from huobi.model.subuser import *
+
+
+class PostSubuserApikeyModificationService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/sub-user/api-key-modification"
+
+ def parse(dict_data):
+ return default_parse(dict_data.get("data", {}), SubuserApikeyModification)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/subuser/post_tradable_market.py b/huobi/service/subuser/post_tradable_market.py
new file mode 100644
index 0000000..4e644eb
--- /dev/null
+++ b/huobi/service/subuser/post_tradable_market.py
@@ -0,0 +1,17 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.subuser.trade_market import TradeMarket
+from huobi.utils import *
+
+
+class PostTradableMarketService:
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/sub-user/tradable-market"
+
+ def parse(dict_data):
+ return default_parse_list_dict(dict_data.get("data", {}), TradeMarket)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
diff --git a/huobi/service/trade/__init__.py b/huobi/service/trade/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/service/trade/get_feerate.py b/huobi/service/trade/get_feerate.py
new file mode 100644
index 0000000..f3c7358
--- /dev/null
+++ b/huobi/service/trade/get_feerate.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.trade import *
+from huobi.utils import *
+
+
+class GetFeeRateService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/fee/fee-rate/get"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, FeeRate, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/get_history_orders.py b/huobi/service/trade/get_history_orders.py
new file mode 100644
index 0000000..eeafe6c
--- /dev/null
+++ b/huobi/service/trade/get_history_orders.py
@@ -0,0 +1,24 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.trade import *
+
+
+class GetHistoryOrdersService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/order/history"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return Order.json_parse_list(data_list)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/get_match_results.py b/huobi/service/trade/get_match_results.py
new file mode 100644
index 0000000..579bde1
--- /dev/null
+++ b/huobi/service/trade/get_match_results.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.trade import *
+from huobi.utils import *
+
+
+class GetMatchResultsService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/order/matchresults"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, MatchResult, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/get_match_results_by_order_id.py b/huobi/service/trade/get_match_results_by_order_id.py
new file mode 100644
index 0000000..84094d5
--- /dev/null
+++ b/huobi/service/trade/get_match_results_by_order_id.py
@@ -0,0 +1,60 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.trade import *
+from huobi.utils import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#client-order-id-2
+成交明细
+API Key 权限:读取
+限频值(NEW):50次/2s
+
+此接口返回指定订单的成交明细。
+
+返回的主数据对象为一个对象数组,其中每一个元件代表一个交易结果。:
+{
+ "data": [
+ {
+ "id": 29553,
+ "order-id": 59378,
+ "match-id": 59335,
+ "trade-id": 100282808529,
+ "symbol": "ethusdt",
+ "type": "buy-limit",
+ "source": "api",
+ "price": "100.1000000000",
+ "filled-amount": "9.1155000000", 成交数量
+ "filled-fees": "0.0182310000", 交易手续费(正值)或交易返佣金(负值)
+ "created-at": 1494901400435, 该成交记录创建的时间戳(略晚于成交时间)
+ "role": "maker",
+ "filled-points": "0.0",
+ “fee-deduct-state”:"done",
+ "fee-deduct-currency": "" 如果为空,代表扣除的手续费是原币;如果为"ht",代表抵扣手续费的是HT;如果为"hbpoint",代表抵扣手续费的是点卡
+ }
+ ...
+ ]
+}
+
+'''
+
+class GetMatchResultsByOrderIdService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ order_id = self.params["order_id"]
+ def get_channel():
+ path = "/v1/order/orders/{}/matchresults"
+ return path.format(order_id)
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, MatchResult, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, get_channel(), self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/get_open_orders.py b/huobi/service/trade/get_open_orders.py
new file mode 100644
index 0000000..c26ce81
--- /dev/null
+++ b/huobi/service/trade/get_open_orders.py
@@ -0,0 +1,41 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.trade import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#75a79bcd48
+查询当前未成交订单
+API Key 权限:读取
+限频值(NEW):50次/2s
+查询已提交但是仍未完全成交或未被撤销的订单。
+
+请求参数:
+account-id 账户 ID,取值参考 GET /v1/account/accounts。现货交易使用‘spot’账户的 account-id;逐仓杠杆交易,请使用 ‘margin’ 账户的 account-id;全仓杠杆交易,请使用 ‘super-margin’ 账户的 account-id;c2c杠杆交易,请使用borrow账户的account-id
+symbol 交易对,即btcusdt, ethbtc...(取值参考GET /v1/common/symbols)
+side 指定只返回某一个方向的订单,可能的值有: buy, sell. 默认两个方向都返回。
+from 查询起始 ID,如果是向后查询,则赋值为上一次查询结果中得到的最后一条id ;如果是向前查询,则赋值为上一次查询结果中得到的第一条id
+direct 查询方向,prev 向前;next 向后 如字段'from'已设定,此字段'direct'为必填
+size 返回订单的数量,最大值500。
+
+
+
+'''
+
+class GetOpenOrdersService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/order/openOrders"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return Order.json_parse_list(data_list)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/get_order_by_client_order_id.py b/huobi/service/trade/get_order_by_client_order_id.py
new file mode 100644
index 0000000..a076e72
--- /dev/null
+++ b/huobi/service/trade/get_order_by_client_order_id.py
@@ -0,0 +1,35 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.trade import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#92d59b6aad
+查询订单详情(基于client order ID)
+API Key 权限:读取
+限频值(NEW):50次/2s
+
+此接口返回指定用户自编订单号(24小时内)的订单最新状态和详情。通过API创建的订单,撤销超过2小时后无法查询。建议通过GET /v1/order/orders/{order-id}来撤单,比使用clientOrderId更快更稳定
+
+
+
+
+'''
+
+class GetOrderByClientOrderIdService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/order/orders/getClientOrder"
+
+ def parse(dict_data):
+ data_dict = dict_data.get("data", {})
+ return Order.json_parse(data_dict)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/get_order_by_id.py b/huobi/service/trade/get_order_by_id.py
new file mode 100644
index 0000000..fbdd269
--- /dev/null
+++ b/huobi/service/trade/get_order_by_id.py
@@ -0,0 +1,59 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.trade import *
+from huobi.utils import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#5f8b337a4c
+查询订单详情
+API Key 权限:读取
+限频值(NEW):50次/2s
+
+此接口返回指定订单的最新状态和详情。通过API创建的订单,撤销超过2小时后无法查询。
+请求参数:
+order-id 订单ID,填在path中
+
+响应数据:
+{
+ "data":
+ {
+ "id": 59378, 订单ID
+ "symbol": "ethusdt", 交易对
+ "account-id": 100009, 账户 ID
+ "amount": "10.1000000000", 订单数量
+ "price": "100.1000000000", 订单价格
+ "created-at": 1494901162595, 订单创建时间
+ "type": "buy-limit", 订单类型
+ "field-amount": "10.1000000000", 已成交数量
+ "field-cash-amount": "1011.0100000000", 已成交总金额
+ "field-fees": "0.0202000000", 已成交手续费(准确数值请参考matchresults接口)
+ "finished-at": 1494901400468, 订单变为终结态的时间,不是成交时间,包含“已撤单”状态
+ "user-id": 1000,
+ "source": "api", 订单来源
+ "state": "filled", 订单状态
+ "canceled-at": 0 订单撤销时间
+ }
+}
+'''
+
+class GetOrderByIdService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ order_id = self.params["order_id"]
+ def get_channel():
+ path = "/v1/order/orders/{}"
+ return path.format(order_id)
+
+ def parse(dict_data):
+ data_dict = dict_data.get("data")
+ return Order.json_parse(data_dict)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, get_channel(), self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/get_orders.py b/huobi/service/trade/get_orders.py
new file mode 100644
index 0000000..958b0e6
--- /dev/null
+++ b/huobi/service/trade/get_orders.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.trade import *
+from huobi.utils import *
+
+
+class GetOrdersService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/order/orders"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return Order.json_parse_list(data_list)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/get_transact_feerate.py b/huobi/service/trade/get_transact_feerate.py
new file mode 100644
index 0000000..9113dee
--- /dev/null
+++ b/huobi/service/trade/get_transact_feerate.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant.system import HttpMethod
+from huobi.model.trade import *
+from huobi.utils import *
+
+
+class GetTransactFeeRateService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/reference/transact-fee-rate"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, TransactFeeRate, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/post_batch_cancel_open_order.py b/huobi/service/trade/post_batch_cancel_open_order.py
new file mode 100644
index 0000000..d8c7656
--- /dev/null
+++ b/huobi/service/trade/post_batch_cancel_open_order.py
@@ -0,0 +1,56 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.trade import *
+from huobi.utils import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#95f2078356
+批量撤销所有订单
+API Key 权限:交易
+限频值(NEW):50次/2s
+
+此接口发送批量撤销所有(单次最大100个)订单的请求。
+此接口只提交取消请求,实际取消结果需要通过订单状态,撮合状态等接口来确认。
+请求参数:
+account-id 账户ID,取值参考 GET /v1/account/accounts
+symbol 交易代码列表(最多10 个symbols,多个交易代码间以逗号分隔),btcusdt, ethbtc...(取值参考/v1/common/symbols)
+types 订单类型组合,使用逗号分割
+side “buy”或“sell”,缺省将返回所有符合条件尚未成交订单
+size 撤销订单的数量 [0,100] 默认值100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+'''
+
+class PostBatchCancelOpenOrderService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/order/orders/batchCancelOpenOrders"
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ return default_parse(data, BatchCancelCount)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/post_batch_cancel_order.py b/huobi/service/trade/post_batch_cancel_order.py
new file mode 100644
index 0000000..ab599af
--- /dev/null
+++ b/huobi/service/trade/post_batch_cancel_order.py
@@ -0,0 +1,38 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils import *
+from huobi.model.trade import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#b9af010185
+批量撤销指定订单
+API Key 权限:交易
+限频值(NEW):50次/2s
+此接口同时为多个订单(基于id)发送取消请求,建议通过order-ids来撤单,比client-order-ids更快更稳定。
+请求参数:
+order-ids 订单编号列表(order-ids和client-order-ids必须且只能选一个填写,不超过50张订单),建议通过order-ids来撤单,比client-order-ids更快更稳定
+client-order-ids 用户自编订单号列表(order-ids和client-order-ids必须且只能选一个填写,不超过50张订单),必须已有该订单存在,否则下次下单时不允许用此值
+
+
+
+'''
+
+
+class PostBatchCancelOrderService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/order/orders/batchcancel"
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ return default_parse_fill_directly(data, BatchCancelResult)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/post_batch_create_order.py b/huobi/service/trade/post_batch_create_order.py
new file mode 100644
index 0000000..a56c6e4
--- /dev/null
+++ b/huobi/service/trade/post_batch_create_order.py
@@ -0,0 +1,32 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.trade.batch_create_order import BatchCreateOrder
+from huobi.utils import *
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#fd6ce2a756
+批量下单
+API Key 权限:交易
+限频值(NEW):50次/2s
+
+一个批量最多10张订单
+
+'''
+class PostBatchCreateOrderService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/order/batch-orders"
+
+ def parse(dict_data):
+ data = dict_data.get("data", [])
+ return default_parse_list_dict(data, BatchCreateOrder, [])
+
+ return RestApiSyncClient(**kwargs).request_process_post_batch(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/post_cancel_client_order.py b/huobi/service/trade/post_cancel_client_order.py
new file mode 100644
index 0000000..7542f94
--- /dev/null
+++ b/huobi/service/trade/post_cancel_client_order.py
@@ -0,0 +1,33 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import default_parse_data_as_long
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#4e53c0fccd
+撤销订单(基于client order ID)
+API Key 权限:交易
+限频值(NEW):100次/2s
+
+此接口基于client-order-id(24小时内有效)发送一个撤销订单的请求。
+撤单个订单建议通过接口/v1/order/orders/{order-id}/submitcancel,会更快更稳定
+请求参数:
+client-order-id 用户自编订单号,必须24小时内已有该订单存在,否则下次下单时不允许用此值
+'''
+
+class PostCancelClientOrderService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/order/orders/submitCancelClientOrder"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/post_cancel_order.py b/huobi/service/trade/post_cancel_order.py
new file mode 100644
index 0000000..5873d35
--- /dev/null
+++ b/huobi/service/trade/post_cancel_order.py
@@ -0,0 +1,49 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import default_parse_data_as_long
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#de93fae07b
+API Key 权限:交易
+限频值(NEW):100次/2s
+
+此接口发送一个撤销订单的请求。
+此接口只提交取消请求,实际取消结果需要通过订单状态,撮合状态等接口来确认。
+
+请求参数:
+order-id 订单ID,填在path中
+
+Success response:
+{
+ "data": "59378" 返回的主数据对象是一个对应下单单号的字符串。
+}
+
+Failure response:
+{
+ "status": "error",
+ "err-code": "order-orderstate-error",
+ "err-msg": "订单状态错误",
+ "order-state":-1 // 当前订单状态
+}
+'''
+
+class PostCancelOrderService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ order_id = self.params["order_id"]
+
+ def get_channel():
+ path = "/v1/order/orders/{}/submitcancel"
+ return path.format(order_id)
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, get_channel(), self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/post_create_order.py b/huobi/service/trade/post_create_order.py
new file mode 100644
index 0000000..158d740
--- /dev/null
+++ b/huobi/service/trade/post_create_order.py
@@ -0,0 +1,57 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.utils.json_parser import default_parse_data_as_long
+'''
+https://huobiapi.github.io/docs/spot/v1/cn/#5ea2e0cde2-7
+下单
+API Key 权限:交易 限频值;100次/2s
+发送一个新订单到火币以进行撮合。
+请求参数:
+account-id 账户 ID,取值参考 GET /v1/account/accounts。现货交易使用 ‘spot’ 账户的 account-id;逐仓杠杆交易,请使用 ‘margin’ 账户的 account-id;全仓杠杆交易,请使用 ‘super-margin’ 账户的 account-id
+symbol 交易对,即btcusdt, ethbtc...(取值参考GET /v1/common/symbols)
+type 订单类型,包括buy-market, sell-market, buy-limit, sell-limit, buy-ioc, sell-ioc, buy-limit-maker, sell-limit-maker(说明见下文), buy-stop-limit, sell-stop-limit, buy-limit-fok, sell-limit-fok, buy-stop-limit-fok, sell-stop-limit-fok
+amount 订单交易量(市价买单为订单交易额)
+price 订单价格(对市价单无效)
+source 现货交易填写“spot-api”,逐仓杠杆交易填写“margin-api”,全仓杠杆交易填写“super-margin-api”, C2C杠杆交易填写"c2c-margin-api"
+client-order-id 用户自编订单号(最大长度64个字符,须在24小时内保持唯一性)
+stop-price 止盈止损订单触发价格
+operator 止盈止损订单触发价运算符 gte – greater than and equal (>=), lte – less than and equal (<=)
+
+buy-limit-maker
+当“下单价格”>=“市场最低卖出价”,订单提交后,系统将拒绝接受此订单;
+当“下单价格”<“市场最低卖出价”,提交成功后,此订单将被系统接受。
+
+sell-limit-maker
+当“下单价格”<=“市场最高买入价”,订单提交后,系统将拒绝接受此订单;
+当“下单价格”>“市场最高买入价”,提交成功后,此订单将被系统接受。
+
+响应数据:
+{
+ "account-id": "100009",
+ "amount": "10.1",
+ "price": "100.1",
+ "source": "api",
+ "symbol": "ethusdt",
+ "type": "buy-limit",
+ "client-order-id": "a0001" 如client order ID(在24小时内)被复用,节点将返回错误消息invalid.client.order.id。
+}
+'''
+
+class PostCreateOrderService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/order/orders/place"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/post_transfer_futures_pro.py b/huobi/service/trade/post_transfer_futures_pro.py
new file mode 100644
index 0000000..0723221
--- /dev/null
+++ b/huobi/service/trade/post_transfer_futures_pro.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.trade import *
+from huobi.utils import *
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostTransferFuturesProService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/futures/transfer"
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/trade/req_order_detail.py b/huobi/service/trade/req_order_detail.py
new file mode 100644
index 0000000..9f2df0c
--- /dev/null
+++ b/huobi/service/trade/req_order_detail.py
@@ -0,0 +1,35 @@
+
+
+from huobi.connection.websocket_req_client import *
+from huobi.model.trade import *
+from huobi.utils import *
+
+
+class ReqOrderDetailService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ order_id = self.params["order-id"]
+ client_req_id = self.params["cid"]
+
+ def subscription(connection):
+ connection.send(request_order_detail_channel(order_id, client_req_id))
+
+ def parse(dict_data):
+ order_update_event = default_parse(dict_data, OrderDetailReq, OrderListItem)
+
+ return order_update_event
+
+ WebSocketReqClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler,
+ is_trade=True)
+
+
+
+
+
+
+
diff --git a/huobi/service/trade/req_order_list.py b/huobi/service/trade/req_order_list.py
new file mode 100644
index 0000000..51a63c0
--- /dev/null
+++ b/huobi/service/trade/req_order_list.py
@@ -0,0 +1,38 @@
+import time
+
+
+from huobi.connection.websocket_req_client import *
+from huobi.model.trade import *
+from huobi.utils import *
+
+
+class ReqOrderListService:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol = self.params["symbol"]
+ account_id = self.params["account-id"]
+ order_states = self.params["states"]
+ client_req_id = self.params["client-req-id"]
+
+ def subscription(connection):
+ connection.send(request_order_list_channel(symbol=symbol, account_id=account_id, states_str=order_states, client_req_id=client_req_id, more_key=self.params))
+
+ def parse(dict_data):
+ order_update_event = default_parse(dict_data, OrderListReq, OrderListItem)
+
+ return order_update_event
+
+ WebSocketReqClient(**kwargs).execute_subscribe_v1(subscription,
+ parse,
+ callback,
+ error_handler,
+ is_trade=True)
+
+
+
+
+
+
+
diff --git a/huobi/service/trade/sub_order_update_v2.py b/huobi/service/trade/sub_order_update_v2.py
new file mode 100644
index 0000000..406e3fe
--- /dev/null
+++ b/huobi/service/trade/sub_order_update_v2.py
@@ -0,0 +1,35 @@
+import time
+
+
+from huobi.connection.subscribe_client import SubscribeClient
+from huobi.model.trade import *
+from huobi.utils import *
+
+
+class SubOrderUpdateV2Service:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+
+ def subscription(connection):
+ for val in symbol_list:
+ connection.send(orders_update_channel(val))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return default_parse(dict_data, OrderUpdateEvent, OrderUpdate)
+
+ SubscribeClient(**kwargs).execute_subscribe_v2(subscription,
+ parse,
+ callback,
+ error_handler,
+ is_trade=True)
+
+
+
+
+
+
+
diff --git a/huobi/service/trade/sub_trade_clearing_v2.py b/huobi/service/trade/sub_trade_clearing_v2.py
new file mode 100644
index 0000000..520fd54
--- /dev/null
+++ b/huobi/service/trade/sub_trade_clearing_v2.py
@@ -0,0 +1,35 @@
+import time
+
+
+from huobi.connection.subscribe_client import SubscribeClient
+from huobi.model.trade import *
+from huobi.utils import *
+
+
+class SubTradeClearingV2Service:
+ def __init__(self, params):
+ self.params = params
+
+ def subscribe(self, callback, error_handler, **kwargs):
+ symbol_list = self.params["symbol_list"]
+
+ def subscription(connection):
+ for symbol in symbol_list:
+ connection.send(trade_clearing_channel(symbol))
+ time.sleep(0.01)
+
+ def parse(dict_data):
+ return TradeClearingEvent.json_parse(dict_data)
+
+ SubscribeClient(**kwargs).execute_subscribe_v2(subscription,
+ parse,
+ callback,
+ error_handler,
+ is_trade=True)
+
+
+
+
+
+
+
diff --git a/huobi/service/wallet/__init__.py b/huobi/service/wallet/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/huobi/service/wallet/get_account_deposit_address.py b/huobi/service/wallet/get_account_deposit_address.py
new file mode 100644
index 0000000..33b2bb8
--- /dev/null
+++ b/huobi/service/wallet/get_account_deposit_address.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.wallet import *
+from huobi.utils import *
+
+
+class GetAccountDepositAddressService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/account/deposit/address"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, ChainDepositAddress)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/wallet/get_account_withdraw_address.py b/huobi/service/wallet/get_account_withdraw_address.py
new file mode 100644
index 0000000..ade6e3a
--- /dev/null
+++ b/huobi/service/wallet/get_account_withdraw_address.py
@@ -0,0 +1,25 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.wallet import *
+from huobi.utils import *
+
+
+class GetAccountWithdrawAddressService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/account/withdraw/address"
+
+ def parse(dict_data):
+ data_list = dict_data.get("data", [])
+ return default_parse_list_dict(data_list, ChainWithdrawAddress)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/wallet/get_account_withdraw_quota.py b/huobi/service/wallet/get_account_withdraw_quota.py
new file mode 100644
index 0000000..18d0b20
--- /dev/null
+++ b/huobi/service/wallet/get_account_withdraw_quota.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.wallet import *
+from huobi.utils import *
+
+
+class GetAccountWithdrawQuotaService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/account/withdraw/quota"
+
+ def parse(dict_data):
+ data = dict_data.get("data", {})
+ chains = data.get("chains", [])
+ return default_parse_list_dict(chains, WithdrawQuota)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/wallet/get_deposit_withdraw.py b/huobi/service/wallet/get_deposit_withdraw.py
new file mode 100644
index 0000000..a011af8
--- /dev/null
+++ b/huobi/service/wallet/get_deposit_withdraw.py
@@ -0,0 +1,30 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.wallet import *
+from huobi.utils import *
+
+
+class GetDepositWithdrawService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/query/deposit-withdraw"
+
+ def parse(dict_data):
+ op_type = self.params["type"]
+ data_list = dict_data.get("data", [])
+ if op_type == DepositWithdraw.DEPOSIT:
+ return default_parse_list_dict(data_list, Deposit)
+ elif op_type == DepositWithdraw.WITHDRAW:
+ return default_parse_list_dict(data_list, Withdraw)
+ return []
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/wallet/get_sub_user_deposit_address.py b/huobi/service/wallet/get_sub_user_deposit_address.py
new file mode 100644
index 0000000..374b729
--- /dev/null
+++ b/huobi/service/wallet/get_sub_user_deposit_address.py
@@ -0,0 +1,22 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.wallet import *
+from huobi.utils import *
+
+
+class GetSubUserDepositAddressService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/sub-user/deposit-address"
+
+ def parse(dict_data):
+ json_data_list = dict_data.get("data", [])
+ return default_parse_list_dict(json_data_list, ChainDepositAddress, [])
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
diff --git a/huobi/service/wallet/get_sub_user_deposit_history.py b/huobi/service/wallet/get_sub_user_deposit_history.py
new file mode 100644
index 0000000..401160d
--- /dev/null
+++ b/huobi/service/wallet/get_sub_user_deposit_history.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.wallet import *
+from huobi.utils import *
+
+
+class GetSubUserDepositHistoryService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v2/sub-user/query-deposit"
+
+ def parse(dict_data):
+ deposit_history = DepositHistory()
+ deposit_history.nextId = dict_data.get("nextId", 0)
+ json_data_list = dict_data.get("data", [])
+ deposit_history_item_list = default_parse_list_dict(json_data_list, DepositHistoryItem)
+ deposit_history.data = deposit_history_item_list
+ return deposit_history
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.GET_SIGN, channel, self.params, parse)
+
+
+
diff --git a/huobi/service/wallet/post_cancel_withdraw.py b/huobi/service/wallet/post_cancel_withdraw.py
new file mode 100644
index 0000000..1141aca
--- /dev/null
+++ b/huobi/service/wallet/post_cancel_withdraw.py
@@ -0,0 +1,28 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.trade import *
+from huobi.utils import *
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostCancelWithdrawService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ withdraw_id_params = self.params["withdraw-id"]
+ def get_channel():
+ path = "/v1/dw/withdraw-virtual/{}/cancel"
+ return path.format(withdraw_id_params)
+
+ def parse(dict_data):
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, get_channel(), self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/service/wallet/post_create_withdraw.py b/huobi/service/wallet/post_create_withdraw.py
new file mode 100644
index 0000000..7fb66cb
--- /dev/null
+++ b/huobi/service/wallet/post_create_withdraw.py
@@ -0,0 +1,26 @@
+from huobi.connection.restapi_sync_client import RestApiSyncClient
+from huobi.constant import *
+from huobi.model.trade import *
+from huobi.utils import *
+from huobi.utils.json_parser import default_parse_data_as_long
+
+
+class PostCreateWithdrawService:
+
+ def __init__(self, params):
+ self.params = params
+
+ def request(self, **kwargs):
+ channel = "/v1/dw/withdraw/api/create"
+
+ def parse(dict_data):
+ # return dict_data.get("data", 0)
+ return default_parse_data_as_long(dict_data, None)
+
+ return RestApiSyncClient(**kwargs).request_process(HttpMethod.POST_SIGN, channel, self.params, parse)
+
+
+
+
+
+
diff --git a/huobi/utils/__init__.py b/huobi/utils/__init__.py
new file mode 100644
index 0000000..7bf0054
--- /dev/null
+++ b/huobi/utils/__init__.py
@@ -0,0 +1,11 @@
+from huobi.utils.print_mix_object import PrintMix, PrintBasic, PrintList
+from huobi.utils.channels import *
+from huobi.utils.channels_request import *
+from huobi.utils.json_parser import default_parse, default_parse_list_dict, default_parse_fill_directly
+from huobi.utils.api_signature import create_signature, utc_now
+from huobi.utils.api_signature_v2 import create_signature_v2, utc_now
+from huobi.utils.url_params_builder import UrlParamsBuilder
+from huobi.utils.time_service import get_current_timestamp, convert_cst_in_millisecond_to_utc, convert_cst_in_second_to_utc
+from huobi.utils.input_checker import check_symbol, check_symbol_list, check_currency, check_range, check_should_none, \
+ check_should_not_none, check_list, greater_or_equal, format_date
+from huobi.utils.log_info import LogLevel, LogInfo
diff --git a/huobi/utils/api_signature.py b/huobi/utils/api_signature.py
new file mode 100644
index 0000000..bb3e22c
--- /dev/null
+++ b/huobi/utils/api_signature.py
@@ -0,0 +1,36 @@
+import base64
+import hashlib
+import hmac
+import datetime
+from urllib import parse
+import urllib.parse
+from huobi.exception.huobi_api_exception import HuobiApiException
+
+
+def create_signature(api_key, secret_key, method, url, builder):
+ if api_key is None or secret_key is None or api_key == "" or secret_key == "":
+ raise HuobiApiException(HuobiApiException.KEY_MISSING, "API key and secret key are required")
+
+ timestamp = utc_now()
+ builder.put_url("AccessKeyId", api_key)
+ builder.put_url("SignatureVersion", "2")
+ builder.put_url("SignatureMethod", "HmacSHA256")
+ builder.put_url("Timestamp", timestamp)
+
+ host = urllib.parse.urlparse(url).hostname
+ path = urllib.parse.urlparse(url).path
+
+ # 对参数进行排序:
+ keys = sorted(builder.param_map.keys())
+ # 加入&
+ qs0 = '&'.join(['%s=%s' % (key, parse.quote(builder.param_map[key], safe='')) for key in keys])
+ # 请求方法,域名,路径,参数 后加入`\n`
+ payload0 = '%s\n%s\n%s\n%s' % (method, host, path, qs0)
+ dig = hmac.new(secret_key.encode('utf-8'), msg=payload0.encode('utf-8'), digestmod=hashlib.sha256).digest()
+ # 进行base64编码
+ s = base64.b64encode(dig).decode()
+ builder.put_url("Signature", s)
+
+
+def utc_now():
+ return datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S')
diff --git a/huobi/utils/api_signature_v2.py b/huobi/utils/api_signature_v2.py
new file mode 100644
index 0000000..c5e1bbd
--- /dev/null
+++ b/huobi/utils/api_signature_v2.py
@@ -0,0 +1,60 @@
+import base64
+import hashlib
+import hmac
+import datetime
+from urllib import parse
+import urllib.parse
+from huobi.exception.huobi_api_exception import HuobiApiException
+
+
+def create_signature_v2(api_key, secret_key, method, url, builder):
+ if api_key is None or secret_key is None or api_key == "" or secret_key == "":
+ raise HuobiApiException(HuobiApiException.KEY_MISSING, "API key and secret key are required")
+
+ timestamp = utc_now()
+ builder.put_url("accessKey", api_key)
+ builder.put_url("signatureVersion", "2.1")
+ builder.put_url("signatureMethod", "HmacSHA256")
+ builder.put_url("timestamp", timestamp)
+
+ host = urllib.parse.urlparse(url).hostname
+ path = urllib.parse.urlparse(url).path
+
+ # 对参数进行排序:
+ keys = sorted(builder.param_map.keys())
+ # 加入&
+ qs0 = '&'.join(['%s=%s' % (key, parse.quote(builder.param_map[key], safe='')) for key in keys])
+ # 请求方法,域名,路径,参数 后加入`\n`
+ payload0 = '%s\n%s\n%s\n%s' % (method, host, path, qs0)
+ dig = hmac.new(secret_key.encode('utf-8'), msg=payload0.encode('utf-8'), digestmod=hashlib.sha256).digest()
+ # 进行base64编码
+ s = base64.b64encode(dig).decode()
+ builder.put_url("signature", s)
+ builder.put_url("authType", "api")
+
+ params = {
+ "accessKey": api_key,
+ "signatureVersion": "2.1",
+ "signatureMethod": "HmacSHA256",
+ "timestamp": timestamp,
+ "signature":s,
+ "authType":"api"
+ }
+
+ builder.put_url("action", "req")
+ builder.put_url("ch", "auth")
+ builder.put_url("params", params)
+
+ """
+ # for test
+ ret_maps = {
+ "action": "req",
+ "ch": "auth",
+ "params" : params
+ }
+
+ return json.dumps(ret_maps)
+ """
+
+def utc_now():
+ return datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S')
diff --git a/huobi/utils/channel_parser.py b/huobi/utils/channel_parser.py
new file mode 100644
index 0000000..3e29e70
--- /dev/null
+++ b/huobi/utils/channel_parser.py
@@ -0,0 +1,5 @@
+class ChannelParser:
+ def __init__(self, input):
+ fields = input.split(".")
+ if len(fields) >= 2:
+ self.symbol = fields[1]
diff --git a/huobi/utils/channels.py b/huobi/utils/channels.py
new file mode 100644
index 0000000..96dfac1
--- /dev/null
+++ b/huobi/utils/channels.py
@@ -0,0 +1,83 @@
+import json
+from huobi.utils.time_service import get_current_timestamp
+from huobi.constant import DepthStep
+
+
+def kline_channel(symbol, interval):
+ channel = dict()
+ channel["sub"] = "market." + symbol + ".kline." + interval
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+
+def trade_detail_channel(symbol):
+ channel = dict()
+ channel["sub"] = "market." + symbol + ".trade.detail"
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+
+def price_depth_channel(symbol, step_type=DepthStep.STEP0):
+ channel = dict()
+ channel["sub"] = "market." + symbol + ".depth." + step_type
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+
+def price_depth_bbo_channel(symbol):
+ channel = dict()
+ channel["sub"] = "market." + symbol + ".bbo"
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+
+def orders_update_channel(symbol):
+ channel = dict()
+ channel["action"] = "sub"
+ channel["ch"] = "orders#{symbol}".format(symbol=symbol)
+ return json.dumps(channel)
+
+
+def market_detail_channel(symbol):
+ channel = dict()
+ channel["sub"] = "market." + symbol + ".detail"
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+
+def accounts_update_channel(mode=0):
+ channel = dict()
+ channel["action"] = "sub"
+ if mode is None:
+ channel["ch"] = "accounts.update"
+ else:
+ channel["ch"] = "accounts.update#{mode}".format(mode=mode)
+ return json.dumps(channel)
+
+
+def mbp_increase_channel(symbol, levels):
+ channel = dict()
+ channel["sub"] = "market.{symbol}.mbp.{levels}".format(symbol=symbol, levels=levels)
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+
+def mbp_full_channel(symbol, levels):
+ channel = dict()
+ channel["sub"] = "market.{symbol}.mbp.refresh.{levels}".format(symbol=symbol, levels=levels)
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+
+def request_mbp_channel(symbol, levels):
+ channel = dict()
+ channel["req"] = "market.{symbol}.mbp.{levels}".format(symbol=symbol, levels=levels)
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+
+def trade_clearing_channel(symbol="*"):
+ channel = dict()
+ channel["action"] = "sub"
+ channel["ch"] = "trade.clearing#" + symbol
+ return json.dumps(channel)
diff --git a/huobi/utils/channels_request.py b/huobi/utils/channels_request.py
new file mode 100644
index 0000000..a9b14b2
--- /dev/null
+++ b/huobi/utils/channels_request.py
@@ -0,0 +1,79 @@
+import json
+from huobi.utils.time_service import get_current_timestamp
+
+def dict_add_new(old_dict, new_dict):
+ if old_dict is None:
+ old_dict = {}
+
+ if new_dict and len(new_dict):
+ for key_val, val in new_dict.items():
+ if val:
+ exist_val = old_dict.get(key_val, None)
+ if exist_val and len(str(exist_val)):
+ pass
+ else:
+ old_dict[key_val] = str(val)
+
+ return old_dict
+
+def request_kline_channel(symbol, interval, from_ts_second = None, to_ts_second = None):
+ channel = dict()
+ channel["req"] = "market." + symbol + ".kline." + interval
+ channel["id"] = str(get_current_timestamp())
+ if from_ts_second:
+ channel["from"] = int(from_ts_second)
+ if to_ts_second:
+ channel["to"] = int(to_ts_second)
+ return json.dumps(channel)
+
+
+def request_trade_detail_channel(symbol):
+ channel = dict()
+ channel["req"] = "market." + symbol + ".trade.detail"
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+
+def request_price_depth_channel(symbol, step_type = "step0"):
+ channel = dict()
+ channel["req"] = "market." + symbol + ".depth." + step_type
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+def request_market_detail_channel(symbol):
+ channel = dict()
+ channel["req"] = "market." + symbol + ".detail"
+ channel["id"] = str(get_current_timestamp())
+ return json.dumps(channel)
+
+def request_account_list_channel(client_req_id = None):
+ channel = dict()
+ channel["op"] = "req"
+ channel["topic"] = "accounts.list"
+ channel["cid"] = str(client_req_id) if client_req_id else str(get_current_timestamp())
+ return json.dumps(channel)
+
+def request_order_list_channel(symbol, account_id, states_str= None, client_req_id = None, more_key={}):
+ channel = dict()
+ try:
+ channel["op"] = "req"
+ channel["account-id"] = account_id
+ channel["topic"] = "orders.list"
+ channel["symbol"] = symbol
+ if states_str and len(states_str):
+ channel["states"] = str(states_str)
+ channel["cid"] = str(client_req_id) if client_req_id else str(get_current_timestamp())
+ channel = dict_add_new(channel, more_key)
+
+ except Exception as e:
+ print(e)
+ return json.dumps(channel)
+
+def request_order_detail_channel(order_id, client_req_id = None):
+ channel = dict()
+ channel["op"] = "req"
+ channel["topic"] = "orders.detail"
+ channel["order-id"] = str(order_id)
+ channel["cid"] = str(client_req_id) if client_req_id else str(get_current_timestamp())
+ return json.dumps(channel)
+
diff --git a/huobi/utils/etf_result.py b/huobi/utils/etf_result.py
new file mode 100644
index 0000000..fdf693c
--- /dev/null
+++ b/huobi/utils/etf_result.py
@@ -0,0 +1,29 @@
+def etf_result_check(code):
+ code = int(code)
+ if code == 200:
+ return ""
+ elif code == 10400:
+ return "Invalid ETF name"
+ elif code == 13403:
+ return "Insufficient asset to create ETF"
+ elif code == 13404:
+ return "Create and redemption disabled due to system setup"
+ elif code == 13405:
+ return "Create and redemption disabled due to configuration issue"
+ elif code == 13406:
+ return "Invalid API call"
+ elif code == 13410:
+ return "API authentication fails"
+ elif code == 13500:
+ return "System error"
+ elif code == 13601:
+ return "Create and redemption disabled during rebalance"
+ elif code == 13603:
+ return "Create and redemption disabled due to other reason"
+ elif code == 13604:
+ return "Create suspended"
+ elif code == 13605:
+ return "Redemption suspended"
+ elif code == 13606:
+ return "Amount incorrect. For the cases when creation amount or redemption amount is not in the range of min/max amount"
+ return ""
diff --git a/huobi/utils/input_checker.py b/huobi/utils/input_checker.py
new file mode 100644
index 0000000..2de456c
--- /dev/null
+++ b/huobi/utils/input_checker.py
@@ -0,0 +1,90 @@
+import re
+import time
+from huobi.exception.huobi_api_exception import HuobiApiException
+from huobi.constant.definition import *
+
+reg_ex = "[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]|\n|\t"
+
+
+def check_symbol(symbol):
+ if not isinstance(symbol, str):
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] symbol must be string")
+ if re.match(reg_ex, symbol):
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] " + symbol + " is invalid symbol")
+
+
+def check_time_in_force(time_in_force, order_type):
+ if time_in_force is None:
+ return
+
+ if order_type in [OrderType.BUY_MARKET, OrderType.SELL_MARKET] \
+ and time_in_force in [TimeInForceType.GTC, TimeInForceType.BOC, TimeInForceType.FOK]:
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] timeInForce not supported for market order")
+
+
+def check_symbol_list(symbols):
+ if not isinstance(symbols, list):
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] symbols in subscription is not a list")
+ for symbol in symbols:
+ check_symbol(symbol)
+
+
+def check_currency(currency):
+ if not isinstance(currency, str):
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] currency must be string")
+ if re.match(reg_ex, currency) is not None:
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] " + currency + " is invalid currency")
+
+
+def check_range(value, min_value, max_value, name):
+ if value is None:
+ return
+ if min_value > value or value > max_value:
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR,
+ "[Input] " + name + " is out of bound. " + str(value) + " is not in [" + str(
+ min_value) + "," + str(max_value) + "]")
+
+
+def check_should_not_none(value, name):
+ if value is None:
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] " + name + " should not be null")
+
+
+def check_should_none(value, name):
+ if value is not None:
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] " + name + " should be null")
+
+
+def check_in_list(value, list_configed, name):
+ if (value is not None) and (value not in list_configed):
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR,
+ "[Input] " + name + " should be one in " + (",".join(list_configed)))
+
+
+def check_list(list_value, min_value, max_value, name):
+ if list_value is None:
+ return
+ if len(list_value) > max_value:
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR,
+ "[Input] " + name + " is out of bound, the max size is " + str(max_value))
+ if len(list_value) < min_value:
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR,
+ "[Input] " + name + " should contain " + str(min_value) + " item(s) at least")
+
+
+def greater_or_equal(value, base, name):
+ if value is not None and value < base:
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR,
+ "[Input] " + name + " should be greater than " + base)
+
+
+def format_date(value, name):
+ if value is None:
+ return None
+ if not isinstance(value, str):
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] " + name + " must be string")
+ try:
+ new_time = time.strptime(value, "%Y-%m-%d")
+ return time.strftime("%Y-%m-%d", new_time)
+ except:
+ raise HuobiApiException(HuobiApiException.INPUT_ERROR, "[Input] " + name + " is not invalid date format")
diff --git a/huobi/utils/json_parser.py b/huobi/utils/json_parser.py
new file mode 100644
index 0000000..61c38fb
--- /dev/null
+++ b/huobi/utils/json_parser.py
@@ -0,0 +1,122 @@
+from huobi.utils.print_mix_object import *
+
+
+def key_trans(key_origin):
+ if key_origin and len(key_origin) > 1:
+ return key_origin.replace("-", "_")
+ else:
+ return ""
+
+
+def fill_obj(dict_data, class_name=object):
+ obj = class_name()
+ for ks, vs in dict_data.items():
+ obj_key = key_trans(ks)
+ # print("===== fill_obj =====", ks, obj_key, str(vs))
+ if hasattr(obj, obj_key):
+ setattr(obj, obj_key, vs)
+ continue
+ return obj
+
+
+def fill_obj_list(list_data, class_name):
+ if (TypeCheck.is_list(list_data)):
+ inner_obj_list = list()
+ for idx, row in enumerate(list_data):
+ inner_obj = fill_obj(row, class_name)
+ inner_obj_list.append(inner_obj)
+ return inner_obj_list
+
+ return list()
+
+
+def default_parse(dict_data, outer_class_name=object, inner_class_name=object):
+ from huobi.utils.print_mix_object import TypeCheck
+ rsp_obj = outer_class_name()
+
+ for outer_key, outer_value in dict_data.items():
+ obj_key = key_trans(outer_key)
+ # print("===", outer_key, obj_key, str(outer_value))
+ # PrintBasic.print_basic_bool(hasattr(rsp_obj, obj_key))
+ if hasattr(rsp_obj, obj_key):
+ new_value = outer_value
+ # print("==========", type(outer_value), outer_value)
+ if (TypeCheck.is_list(outer_value)):
+ new_value = fill_obj_list(outer_value, inner_class_name)
+ elif (TypeCheck.is_dict(outer_value)):
+ new_value = fill_obj(outer_value, inner_class_name)
+
+ setattr(rsp_obj, obj_key, new_value)
+ continue
+
+ return rsp_obj
+
+
+def default_parse_data_as_long(ret_original_json, key_name=None, default_value=0):
+ if ret_original_json:
+ # from data get value by key_name
+ if key_name and len(key_name):
+ data_json = ret_original_json.get("data", {})
+ ret_val = data_json.get(key_name, default_value)
+ else:
+ # get data value
+ ret_val = ret_original_json.get("data", 0)
+ return None if ret_val is None else int(ret_val)
+ else:
+ return default_value
+
+
+def default_parse_list_dict(inner_data, inner_class_name=object, default_value=None):
+ from huobi.utils.print_mix_object import TypeCheck
+
+ new_value = default_value
+ if inner_data and len(inner_data):
+ if (TypeCheck.is_list(inner_data)):
+ new_value = fill_obj_list(inner_data, inner_class_name)
+ elif (TypeCheck.is_dict(inner_data)):
+ new_value = fill_obj(inner_data, inner_class_name)
+ else:
+ new_value = default_value
+
+ return new_value
+
+
+def default_parse_fill_directly(dict_data, outer_class_name=object):
+ rsp_obj = outer_class_name()
+
+ for outer_key, outer_value in dict_data.items():
+ obj_key = key_trans(outer_key)
+ if hasattr(rsp_obj, obj_key):
+ new_value = outer_value
+ setattr(rsp_obj, obj_key, new_value)
+ continue
+
+ return rsp_obj
+
+
+if __name__ == "__main__":
+ # json_str = """{"id":1571037900,"open":8306.850000000000000000,"close":8307.990000000000000000,"low":8305.800000000000000000,"high":8308.000000000000000000,"amount":4.314954363225502510,"vol":35845.853207199999993966820000000000000000,"count":45}"""
+ # obj = parse(json_str, outer_class_name=Candlestick, inner_class_name=None)
+
+ # obj.print_object()
+
+ # json_str = """{"status":"ok","ch":"market.btcusdt.kline.1min","ts":1571038189274,"data":[{"id":1571038140,"open":8304.130000000000000000,"close":8305.000000000000000000,"low":8300.010000000000000000,"high":8305.000000000000000000,"amount":41.791380418639796061,"vol":347038.873910589999990613890000000000000000,"count":165},{"id":1571038080,"open":8306.060000000000000000,"close":8304.130000000000000000,"low":8304.130000000000000000,"high":8306.060000000000000000,"amount":3.440305012281757977,"vol":28571.704804969999998985000000000000000000,"count":70},{"id":1571038020,"open":8303.890000000000000000,"close":8305.990000000000000000,"low":8303.890000000000000000,"high":8307.000000000000000000,"amount":6.164746957847080072,"vol":51200.094613737306439860000000000000000000,"count":89},{"id":1571037960,"open":8308.000000000000000000,"close":8303.660000000000000000,"low":8303.610000000000000000,"high":8308.430000000000000000,"amount":9.449641840557003640,"vol":78488.394246429999983963200000000000000000,"count":128},{"id":1571037900,"open":8306.850000000000000000,"close":8307.990000000000000000,"low":8305.800000000000000000,"high":8308.000000000000000000,"amount":4.314954363225502510,"vol":35845.853207199999993966820000000000000000,"count":45},{"id":1571037840,"open":8305.290000000000000000,"close":8306.820000000000000000,"low":8305.040000000000000000,"high":8307.300000000000000000,"amount":3.661411574656800047,"vol":30412.286333819999984471300000000000000000,"count":68},{"id":1571037780,"open":8306.500000000000000000,"close":8305.490000000000000000,"low":8305.100000000000000000,"high":8307.690000000000000000,"amount":2.958112866447550895,"vol":24569.573928609999984901150000000000000000,"count":59},{"id":1571037720,"open":8306.300000000000000000,"close":8307.560000000000000000,"low":8305.440000000000000000,"high":8309.000000000000000000,"amount":8.506926000000000000,"vol":70665.848347860000000000000000000000000000,"count":90},{"id":1571037660,"open":8306.920000000000000000,"close":8306.300000000000000000,"low":8306.200000000000000000,"high":8307.000000000000000000,"amount":5.084311000000000000,"vol":42233.572201310000000000000000000000000000,"count":57},{"id":1571037600,"open":8307.200000000000000000,"close":8306.920000000000000000,"low":8306.920000000000000000,"high":8309.160000000000000000,"amount":4.540090141728746275,"vol":37715.585646199999989163880000000000000000,"count":54}]}"""
+ # obj_event = parse(json_str, outer_class_name=CandlestickRsp, inner_class_name=Candlestick)
+ # obj_event.print_object()
+
+ # json_str = """{"status":"ok","ch":"market.btcusdt.kline.1min","ts":1571038189274,"data":{"id":1571038140,"open":8304.130000000000000000,"close":8305.000000000000000000,"low":8300.010000000000000000,"high":8305.000000000000000000,"amount":41.791380418639796061,"vol":347038.873910589999990613890000000000000000,"count":165}}"""
+ # obj_event = parse(json_str, outer_class_name=CandlestickEvent, inner_class_name=Candlestick)
+ # obj_event.print_object()
+
+ # json_str = """{"status":"ok","ch":"market.btcusdt.kline.1min","ts":1571038189274,"data":{"id":1571038140,"open":8304.130000000000000000,"close":8305.000000000000000000,"low":8300.010000000000000000,"high":8305.000000000000000000,"amount":41.791380418639796061,"vol":347038.873910589999990613890000000000000000,"count":165}}"""
+ # ret = default_parse_restful(json_str, inner_class_name=Candlestick, default_value=None)
+ # ret.print_object()
+
+ # json_str = """{"status":"ok","ch":"market.btcusdt.kline.1min","ts":1571038189274,"data":[{"id":1571038140,"open":8304.130000000000000000,"close":8305.000000000000000000,"low":8300.010000000000000000,"high":8305.000000000000000000,"amount":41.791380418639796061,"vol":347038.873910589999990613890000000000000000,"count":165},{"id":1571038080,"open":8306.060000000000000000,"close":8304.130000000000000000,"low":8304.130000000000000000,"high":8306.060000000000000000,"amount":3.440305012281757977,"vol":28571.704804969999998985000000000000000000,"count":70},{"id":1571038020,"open":8303.890000000000000000,"close":8305.990000000000000000,"low":8303.890000000000000000,"high":8307.000000000000000000,"amount":6.164746957847080072,"vol":51200.094613737306439860000000000000000000,"count":89},{"id":1571037960,"open":8308.000000000000000000,"close":8303.660000000000000000,"low":8303.610000000000000000,"high":8308.430000000000000000,"amount":9.449641840557003640,"vol":78488.394246429999983963200000000000000000,"count":128},{"id":1571037900,"open":8306.850000000000000000,"close":8307.990000000000000000,"low":8305.800000000000000000,"high":8308.000000000000000000,"amount":4.314954363225502510,"vol":35845.853207199999993966820000000000000000,"count":45},{"id":1571037840,"open":8305.290000000000000000,"close":8306.820000000000000000,"low":8305.040000000000000000,"high":8307.300000000000000000,"amount":3.661411574656800047,"vol":30412.286333819999984471300000000000000000,"count":68},{"id":1571037780,"open":8306.500000000000000000,"close":8305.490000000000000000,"low":8305.100000000000000000,"high":8307.690000000000000000,"amount":2.958112866447550895,"vol":24569.573928609999984901150000000000000000,"count":59},{"id":1571037720,"open":8306.300000000000000000,"close":8307.560000000000000000,"low":8305.440000000000000000,"high":8309.000000000000000000,"amount":8.506926000000000000,"vol":70665.848347860000000000000000000000000000,"count":90},{"id":1571037660,"open":8306.920000000000000000,"close":8306.300000000000000000,"low":8306.200000000000000000,"high":8307.000000000000000000,"amount":5.084311000000000000,"vol":42233.572201310000000000000000000000000000,"count":57},{"id":1571037600,"open":8307.200000000000000000,"close":8306.920000000000000000,"low":8306.920000000000000000,"high":8309.160000000000000000,"amount":4.540090141728746275,"vol":37715.585646199999989163880000000000000000,"count":54}]}"""
+ # ret = default_parse_restful(json_str, inner_class_name=Candlestick, default_value=None)
+ # if ret and len(ret):
+ # for row in ret:
+ # row.print_object()
+ # print("========")
+
+ pass
diff --git a/huobi/utils/log_info.py b/huobi/utils/log_info.py
new file mode 100644
index 0000000..41da0d5
--- /dev/null
+++ b/huobi/utils/log_info.py
@@ -0,0 +1,31 @@
+class LogLevel:
+ DEBUG = "debug"
+ INFO = "info"
+ WARNINGS = "warning"
+ ERROR = "error"
+ FATAL = "fatal"
+
+
+class LogInfo:
+ @staticmethod
+ def output(message, log_level=LogLevel.DEBUG):
+ # if (message and len(message)):
+ # if log_level == LogLevel.DEBUG:
+ # logging.debug(message)
+ # elif log_level == LogLevel.INFO:
+ # logging.info(message)
+ # elif log_level == LogLevel.WARNINGS:
+ # logging.warnings(message)
+ # elif log_level == LogLevel.ERROR:
+ # logging.error(message)
+ # elif log_level == LogLevel.FATAL:
+ # logging.fatal(message)
+
+ print(message)
+
+ @staticmethod
+ def output_list(data_list, log_level=LogLevel.DEBUG):
+ if data_list and len(data_list):
+ for obj in data_list:
+ obj.print_object()
+ print()
diff --git a/huobi/utils/print_mix_object.py b/huobi/utils/print_mix_object.py
new file mode 100644
index 0000000..894dc43
--- /dev/null
+++ b/huobi/utils/print_mix_object.py
@@ -0,0 +1,232 @@
+import sys
+import time
+
+BASIC_DATA_TYPE = (int, str, float)
+BASIC_DATA_TYPE_BOOL = (bool)
+
+TYPE_BASIC = "type_basic"
+TYPE_BOOL = "type_bool"
+TYPE_OBJECT = "type_object"
+TYPE_LIST = "type_list"
+TYPE_DICT = "type_dict"
+TYPE_UNDEFINED = "type_undefined"
+
+
+class TypeCheck:
+ @staticmethod
+ def is_list(obj):
+ return type(obj) == list and isinstance(obj, list)
+
+ @staticmethod
+ def is_dict(obj):
+ return type(obj) == dict and isinstance(obj, dict)
+
+ @staticmethod
+ def is_object(obj):
+ return isinstance(obj, object)
+
+ @staticmethod
+ def is_basic(obj):
+ return isinstance(obj, BASIC_DATA_TYPE)
+
+ @staticmethod
+ def is_bool(obj):
+ return isinstance(obj, bool)
+
+ @staticmethod
+ def get_obj_type(obj):
+ if TypeCheck.is_basic(obj):
+ return TYPE_BASIC
+ elif TypeCheck.is_bool(obj):
+ return TYPE_BOOL
+ elif TypeCheck.is_list(obj):
+ return TYPE_LIST
+ elif TypeCheck.is_dict(obj):
+ return TYPE_DICT
+ elif TypeCheck.is_object(obj):
+ return TYPE_OBJECT
+ else:
+ return TYPE_UNDEFINED
+
+
+class PrintBasic:
+ @staticmethod
+ def print_basic(data, name=None):
+ if name and len(name):
+ print(str(name) + " : " + str(data))
+ else:
+ print(str(data))
+
+ @staticmethod
+ def print_basic_bool(data, name=None):
+ bool_desc = "True"
+ if not data:
+ bool_desc = "False"
+
+ if name and len(name):
+ print(str(name) + " : " + str(bool_desc))
+ else:
+ print(str(bool_desc))
+
+ @staticmethod
+ def print_obj(obj):
+ if not obj:
+ return -1
+
+ members = [attr for attr in dir(obj) if not callable(attr) and not attr.startswith("__")]
+ for member_def in members:
+ val_str = str(getattr(obj, member_def))
+ print(member_def + ":" + val_str)
+ return 0
+
+
+class PrintList:
+ @staticmethod
+ def print_list_data(obj):
+ if not obj:
+ print("object is None")
+ return -1
+
+ if TypeCheck.get_obj_type(obj) == TYPE_LIST:
+ for idx, row in enumerate(obj):
+ PrintBasic.print_basic(row)
+ else:
+ return -2
+
+ return 0
+
+ @staticmethod
+ def print_origin_object(obj):
+ if not obj:
+ print("object is None")
+ return -1
+ obj_type = TypeCheck.get_obj_type(obj)
+
+ if obj_type == TYPE_BASIC:
+ PrintBasic.print_basic(obj)
+ elif obj_type == TYPE_BOOL:
+ PrintBasic.print_basic_bool(obj)
+ elif obj_type == TYPE_OBJECT:
+ PrintBasic.print_obj(obj)
+ else:
+ return 1
+
+ return 0
+
+ @staticmethod
+ def print_object_list(obj_list):
+ if not obj_list:
+ return -1
+
+ obj_type = TypeCheck.get_obj_type(obj_list)
+ if obj_type != TYPE_LIST:
+ return -2
+
+ print ("data count : ", (len(obj_list)))
+ print ("\n")
+ for idx, row in enumerate(obj_list):
+ print("data number " + (str(idx)) + " :")
+ PrintList.print_origin_object(row)
+ print("\n")
+ print("\n\n")
+
+ return 0
+
+ @staticmethod
+ def print_object_dict(obj_dict):
+ if not obj_dict:
+ return -1
+
+ obj_type = TypeCheck.get_obj_type(obj_dict)
+ if obj_type != TYPE_DICT:
+ return -2
+
+ print ("data count : ", (len(obj_dict)))
+ print ("\n")
+ for key, row in obj_dict.items():
+ PrintBasic.print_basic(str(key) + " :")
+ PrintList.print_origin_object(row)
+ print("\n")
+ print("\n\n")
+
+ return 0
+
+
+class PrintMix:
+ @staticmethod
+ def print_data(data):
+ if not data:
+ print (sys._getframe().f_code.co_name + " none data")
+ return -1
+
+ obj_type = TypeCheck.get_obj_type(data)
+
+ if obj_type == TYPE_BASIC:
+ PrintBasic.print_basic(data)
+ elif obj_type == TYPE_BOOL:
+ PrintBasic.print_basic_bool(data)
+ elif obj_type == TYPE_LIST:
+ PrintList.print_object_list(data)
+ elif obj_type == TYPE_DICT:
+ PrintList.print_object_dict(data)
+ elif obj_type == TYPE_OBJECT:
+ PrintList.print_origin_object(data)
+ else:
+ print (sys._getframe().f_code.co_name + " enter unknown")
+ return -2
+
+ return 0
+
+
+
+class PrintDate:
+ @staticmethod
+ def timestamp_to_date(ts_minsecond):
+ try:
+ ts_minsecond = int(ts_minsecond)
+ time_local = time.localtime(int(ts_minsecond / 1000))
+ dt = time.strftime("%Y-%m-%d %H:%M:%S", time_local)
+ print("ping " + str(ts_minsecond) + ":" + dt)
+ except Exception as e:
+ print(e)
+
+"""
+if __name__ == "__main__":
+ ping_ts = 1569319465421
+ PrintDate.timestamp_to_date(ping_ts)
+ PrintDate.timestamp_to_date(int(ping_ts), ("ping " + str(ping_ts)))
+"""
+
+
+if __name__ == "__main__":
+ """
+ from huobi.model.symbol import Symbol
+
+ symbol_1 = Symbol()
+ symbol_1.amount_precision = 10009
+ symbol_1.symbol = "btcusdt"
+
+ symbol_2 = Symbol()
+ symbol_2.amount_precision = 28
+ symbol_2.symbol = "htusdt"
+
+ symbol_3 = Symbol()
+ symbol_3.amount_precision = 26
+ symbol_3.symbol = "eosusdt"
+
+ symbol_list = [symbol_1, symbol_2, symbol_3]
+ symbol_dict = {"one": symbol_1, "two": symbol_2, "three": symbol_3}
+ PrintMix.print_data(symbol_list)
+ PrintMix.print_data(symbol_dict)
+
+ print(type(symbol_list) == list)
+ print(type(symbol_dict) == dict)
+ print(type(symbol_list) == object)
+ print(isinstance(symbol_list, list))
+ print(isinstance(symbol_list, object))
+ print(isinstance(symbol_dict, dict))
+ print(isinstance(symbol_dict, object))
+ """
+
+ a=['s', 'h', 'i']
+ PrintList.print_list_data(a)
diff --git a/huobi/utils/time_service.py b/huobi/utils/time_service.py
new file mode 100644
index 0000000..d2af8e9
--- /dev/null
+++ b/huobi/utils/time_service.py
@@ -0,0 +1,22 @@
+import time
+
+
+def get_current_timestamp():
+ return int(round(time.time() * 1000))
+
+
+def convert_cst_in_second_to_utc(time_in_second):
+ time_in_second = int(time_in_second)
+ if time_in_second > 946656000 and time_in_second < 946656000000:
+ return (time_in_second - 8 * 60 * 60) * 1000
+ else:
+ return 0
+
+
+def convert_cst_in_millisecond_to_utc(time_in_ms):
+ time_in_ms = int(time_in_ms)
+ if time_in_ms > 946656000000:
+ return time_in_ms - 8 * 60 * 60 * 1000
+ else:
+ return 0
+
diff --git a/huobi/utils/url_params_builder.py b/huobi/utils/url_params_builder.py
new file mode 100644
index 0000000..fd689cc
--- /dev/null
+++ b/huobi/utils/url_params_builder.py
@@ -0,0 +1,33 @@
+import json
+import urllib.parse
+
+
+class UrlParamsBuilder(object):
+
+ def __init__(self):
+ self.param_map = dict()
+ self.post_map = dict()
+ self.post_list = list()
+
+ def put_url(self, name, value):
+ if value is not None:
+ if isinstance(value, (list, dict)):
+ self.param_map[name] = value
+ else:
+ self.param_map[name] = str(value)
+
+ def put_post(self, name, value):
+ if value is not None:
+ if isinstance(value, (list, dict)):
+ self.post_map[name] = value
+ else:
+ self.post_map[name] = str(value)
+
+ def build_url(self):
+ if len(self.param_map) == 0:
+ return ""
+ encoded_param = urllib.parse.urlencode(self.param_map)
+ return "?" + encoded_param
+
+ def build_url_to_json(self):
+ return json.dumps(self.param_map)
diff --git a/huobi_alert.py b/huobi_alert.py
new file mode 100644
index 0000000..08e9982
--- /dev/null
+++ b/huobi_alert.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+from utils import utility
+from utils import config
+
+from huobi.client.account import AccountClient
+from huobi.client.trade import TradeClient
+from huobi.constant import *
+from huobi.utils import *
+
+
+
+if __name__ == '__main__':
+
+ config.loads('./conf_huobi/config.json')
+ order_list_submitted = []
+
+ trade_client = TradeClient(api_key=config.api_key, secret_key=config.api_secret)
+ account_client = AccountClient(api_key=config.api_key, secret_key=config.api_secret)
+
+ account_spot = account_client.get_account_by_type_and_symbol(account_type=AccountType.SPOT, symbol=None)
+ account_id_test = account_spot.id
+ direct_tmp = QueryDirection.NEXT
+ LogInfo.output("==============test case 1 for {direct}===============".format(direct=direct_tmp))
+ for symbol in config.symbol_spot:
+ print(symbol)
+ list_obj = trade_client.get_open_orders(symbol=symbol, account_id=account_id_test, direct=direct_tmp)
+ for order in list_obj:
+ if order.state == 'submitted':
+ order_list_submitted.append(str(order.id))
+ print(order.id)
+ print(order)
+ #LogInfo.output_list(list_obj)
+
+
+ # direct_tmp = QueryDirection.PREV
+ # LogInfo.output("==============test case 2 for {direct}===============".format(direct=direct_tmp))
+ # list_obj = trade_client.get_open_orders(symbol=symbol, account_id=account_id_test, direct=direct_tmp)
+ # LogInfo.output_list(list_obj)
+
+
+
+
+ # #启动新实例 发个通知
+ # utility.alert(f"{utility.cn_time()} 火币订单监控启动")
+
+ # while True:
+ # try:
+ # time.sleep(20)
+ #
+ # except Exception as error:
+ # utility.alert(error)
+ # time.sleep(5)
+
diff --git a/k8s.md b/k8s.md
new file mode 100644
index 0000000..f6ecb4d
--- /dev/null
+++ b/k8s.md
@@ -0,0 +1,57 @@
+
+# configmap
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: binance-config-qy-xrp
+ namespace: sre
+data:
+ config.json: |
+ {
+ "platform": "binance_spot",
+ "symbol": "XRPUSDT",
+ "api_key": "your api_ky 1111111111111111111111111111111111111",
+ "api_secret": "your api_secret 222222222222222222222222222222",
+ "gap_percent": 0.005,
+ "quantity": 40,
+ "min_price": 0.00001,
+ "min_qty": 40,
+ "max_orders": 5,
+ "proxy_host": "",
+ "proxy_port": 0
+ }
+```
+
+# k8s Deployment api-wechat
+
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: binance-trader-xrp
+ namespace: sre
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ binance: trader
+ template:
+ metadata:
+ labels:
+ binance: trader
+ spec:
+ imagePullSecrets:
+ - name: wzaqqqaliyunsecret
+ containers:
+ - name: binance-trader
+ image: mmmmmmmmmmmmmmmm/binance_grid_trader:6
+ imagePullPolicy: IfNotPresent
+ volumeMounts:
+ - name: binance-config
+ mountPath: /app/conf/
+ volumes:
+ - name: binance-config
+ configMap:
+ name: binance-config-qy-xrp
+```
diff --git a/main.dev.py b/main.dev.py
new file mode 100644
index 0000000..fe6658f
--- /dev/null
+++ b/main.dev.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+
+import time
+import logging
+from binance.binance_trader import BinanceTrader
+from binance.utils import config
+
+format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+logging.basicConfig(level=logging.INFO, format=format, filename='grid_trader_log.txt')
+logger = logging.getLogger('binance')
+
+
+if __name__ == '__main__':
+
+
+ config.loads('./conf/config.json')
+ trader = BinanceTrader()
+
+
+
+ while True:
+ try:
+ print(trader.get_avg_price_5min())
+ print(trader.get_price_change_percent_24h())
+ #trader.grid_trader()
+ time.sleep(200)
+
+ except Exception as error:
+ print(f"BA catch error: {error}")
+ time.sleep(5)
+
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..ff2ddd2
--- /dev/null
+++ b/main.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+
+import time
+import logging
+from binance.binance_trader import BinanceTrader
+from binance.binance_future_trader import BinanceFutureTrader
+from utils import utility
+from utils import config
+format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+logging.basicConfig(level=logging.INFO, format=format, filename='grid_trader_log.txt')
+logger = logging.getLogger('binance')
+
+
+if __name__ == '__main__':
+
+
+ config.loads('./conf/config.json')
+ sleep_time = 5
+ if config.sleep_time:
+ sleep_time = config.sleep_time
+
+ if config.platform == 'binance_spot':
+ trader = BinanceTrader()
+ else:
+ trader = BinanceFutureTrader()
+
+ #启动新实例, 取消客户端创建的订单
+ print("启动新实例, 同步本客户端创建的订单:")
+ trader.sync_open_orders()
+
+ #启动新实例 发个通知
+ utility.alert(f"{utility.cn_time()} 交易对{config.symbol}启动")
+
+
+
+
+
+ while True:
+ try:
+ trader.grid_trader()
+ time.sleep(sleep_time)
+
+ except Exception as error:
+ utility.alert(f"交易{config.symbol}: {error}")
+ time.sleep(sleep_time)
+
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..48f6028
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,6 @@
+requests==2.22.0
+dingtalkchatbot
+pytz
+APScheduler==3.6.3
+aiohttp
+websocket_client==0.57.0
\ No newline at end of file
diff --git a/test.py b/test.py
new file mode 100644
index 0000000..0bae355
--- /dev/null
+++ b/test.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+
+import time
+from binance.binance_trader import BinanceTrader
+from binance.binance_future_trader import BinanceFutureTrader
+from utils import config
+
+
+
+if __name__ == '__main__':
+
+
+ config.loads('./conf/config.json')
+
+ trader_spot = BinanceTrader()
+ trader_future = BinanceFutureTrader()
+
+
+
+
+ while True:
+ try:
+ price_spot = trader_spot.get_latest_price()
+ price_future = trader_future.get_latest_price()
+ print("diff:")
+ print(f"price_spot:{price_spot} price_future:{price_future}")
+ print(f"spot/future: {price_spot/price_future}")
+ time.sleep(5)
+
+ except Exception as error:
+ print(f"交易{config.symbol}: {error}")
+ time.sleep(5)
+
diff --git a/test1.py b/test1.py
new file mode 100644
index 0000000..d2eed2a
--- /dev/null
+++ b/test1.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python3
+#coding: utf-8
+import smtplib
+from email.mime.text import MIMEText
+sender = '44444444444444444444g'
+receiver = '44444444444444444rg'
+subject = 'python email test'
+smtpserver = '4444444444444444444rg'
+username = '4444444444444444g'
+password = '44444444444444444444444'
+msg = MIMEText('ja2磁盘使用超过80%
','html','utf-8')
+msg['Subject'] = subject
+smtp = smtplib.SMTP()
+smtp.connect(smtpserver)
+smtp.login(username, password)
+smtp.sendmail(sender, receiver, msg.as_string())
+smtp.quit()
diff --git a/test2.py b/test2.py
new file mode 100644
index 0000000..8d16f6f
--- /dev/null
+++ b/test2.py
@@ -0,0 +1,7 @@
+def as_num(x):
+ y='{:.32f}'.format(x) # 5f表示保留5位小数点的float型
+ return(y)
+
+
+
+print(as_num(1.2e-4))
diff --git a/test_depth.py b/test_depth.py
new file mode 100644
index 0000000..294b8fc
--- /dev/null
+++ b/test_depth.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+
+import time
+import logging
+from binance.binance_trader import BinanceTrader
+from binance.binance_future_trader import BinanceFutureTrader
+from utils import utility
+from utils import config
+format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+logging.basicConfig(level=logging.INFO, format=format, filename='grid_trader_log.txt')
+logger = logging.getLogger('binance')
+
+
+if __name__ == '__main__':
+
+
+ config.loads('./conf/config.json')
+
+ if config.platform == 'binance_spot':
+ trader = BinanceTrader()
+ else:
+ trader = BinanceFutureTrader()
+
+
+
+ while True:
+ try:
+ trader.get_depth(5)
+ time.sleep(20)
+
+ except Exception as error:
+ utility.alert(f"交易{config.symbol}: {error}")
+ time.sleep(5)
+
diff --git a/utils/__init__.py b/utils/__init__.py
new file mode 100644
index 0000000..9430428
--- /dev/null
+++ b/utils/__init__.py
@@ -0,0 +1,4 @@
+from .config import config
+from .utility import *
+from .smtp import send_email
+from .dingding import *
\ No newline at end of file
diff --git a/utils/config.py b/utils/config.py
new file mode 100644
index 0000000..1c4f0e6
--- /dev/null
+++ b/utils/config.py
@@ -0,0 +1,54 @@
+# -*- coding:utf-8 -*-
+import json
+
+
+class Config:
+
+ def __init__(self):
+
+ self.platform: str = "binance_spot" # 交易的平台
+ self.symbol:str = "XRPUSDT" # 交易对.
+ self.gap_percent: float = 0.005 # 网格变化交易的单位.
+ self.api_key: str = None
+ self.api_secret: str = None
+ self.pass_phrase = None
+ self.quantity:float = 1
+ self.min_price = 0.0001
+ self.min_qty = 0.01
+ self.max_orders = 1
+ self.proxy_host = "" # proxy host
+ self.proxy_port = 0 # proxy port
+
+
+ def loads(self, config_file=None):
+ """ Load config file.
+
+ Args:
+ config_file: config json file.
+ """
+ configures = {}
+ if config_file:
+ try:
+ with open(config_file) as f:
+ data = f.read()
+ configures = json.loads(data)
+ except Exception as e:
+ print(e)
+ exit(0)
+ if not configures:
+ print("config json file error!")
+ exit(0)
+ self._update(configures)
+
+ def _update(self, update_fields):
+ """
+ 更新update fields.
+ :param update_fields:
+ :return: None
+
+ """
+
+ for k, v in update_fields.items():
+ setattr(self, k, v)
+
+config = Config()
\ No newline at end of file
diff --git a/utils/dingding.py b/utils/dingding.py
new file mode 100644
index 0000000..814fe52
--- /dev/null
+++ b/utils/dingding.py
@@ -0,0 +1,34 @@
+from dingtalkchatbot.chatbot import DingtalkChatbot
+from utils.config import config
+
+def dingding_at_me(msg):
+ # WebHook地址
+ webhook = config.dingding_robot_url
+ #dingding_user = config.dingding_user_phone
+ secret = 'SEC11b9...这里填写自己的加密设置密钥' # 可选:创建机器人勾选“加签”选项时使用
+ # 初始化机器人小丁
+ xiaoding = DingtalkChatbot(webhook) # 方式一:通常初始化方式
+ #xiaoding = DingtalkChatbot(webhook, secret=secret) # 方式二:勾选“加签”选项时使用(v1.5以上新功能)
+ #xiaoding = DingtalkChatbot(webhook, pc_slide=True) # 方式三:设置消息链接在PC端侧边栏打开(v1.5以上新功能)
+ # Text消息@所有人
+ #xiaoding.send_text(msg='我就是小丁,小丁就是我!', is_at_all=True)
+ dingding_user = [config.dingding_user_phone]
+ #xiaoding.send_text(msg=msg, at_mobiles=dingding_user)
+ xiaoding.send_text(msg=msg, at_mobiles=dingding_user)
+
+def dingding_at_all(msg):
+ webhook = config.dingding_robot_url
+ xiaoding = DingtalkChatbot(webhook) # 方式一:通常初始化方式
+ xiaoding.send_text(msg=msg, is_at_all=True)
+
+def dingding_say(msg):
+ webhook = config.dingding_robot_url
+ xiaoding = DingtalkChatbot(webhook) # 方式一:通常初始化方式
+ xiaoding.send_text(msg=msg)
+
+if __name__ == '__main__':
+ config.loads('../conf/config.json')
+ dingding_say("test")
+ print("dingding utils")
+
+
diff --git a/utils/queue.py b/utils/queue.py
new file mode 100644
index 0000000..b5686f3
--- /dev/null
+++ b/utils/queue.py
@@ -0,0 +1,52 @@
+# 先进先出
+class Queue():
+
+ def __init__(self,size):
+ self.size=size
+ self.front=-1 #队列前面的指针
+ self.rear=-1 #队列后面的指针
+ #类中设置两个属性分别为front和rear来模拟队列的头尾指针,通过它们值的关系可以判定队列是空还是满
+ self.queue=[]
+
+ ## 入队操作
+ def enqueue(self,ele):
+ if self.isfull():
+ print("queue is full")
+ else:
+ self.queue.append(ele)
+ self.rear=self.rear+1
+
+ ## 出队操作
+ def dequeue(self):
+ if self.isempty():
+ print("queue is empty")
+ else:
+ self.queue.pop(0)
+ self.front=self.front+1
+
+ def isfull(self):
+ if self.rear - self.front + 1 == self.size :
+ return True
+ else:
+ return False
+ def isempty(self):
+ if self.front == self.rear:
+ return True
+ else:
+ return False
+ def showQueue(self):
+ print(self.queue)
+
+if __name__ == '__main__':
+ q = Queue(10)
+ for i in range(6):
+ #print(i)
+ q.enqueue(i)
+ q.showQueue()
+ for i in range(3):
+ q.dequeue()
+ q.showQueue()
+ print(q.isempty())
+
+
+
diff --git a/utils/smtp.py b/utils/smtp.py
new file mode 100644
index 0000000..75f05ab
--- /dev/null
+++ b/utils/smtp.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+from utils.config import config
+import smtplib
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+from email.header import Header
+
+#自适应邮件标题
+def get_subject(text):
+ default_subject='交易通知'
+ if "买单成交" in text:
+ return "买单成交"
+ elif "卖单成交" in text:
+ return "卖单成交"
+ elif "启动" in text:
+ return "机器人启动"
+ elif "配置不当" in text:
+ return "配置不当"
+ elif "单创建失败" in text:
+ return "订单创建失败"
+ elif "撤销失败" in text:
+ return "订单撤销失败"
+ else:
+ return default_subject
+
+
+#发出邮件
+def send_email(text):
+ #连接邮箱服务器
+ #con = smtplib.SMTP_SSL('mail.yangqiao.org', 465)
+ con = smtplib.SMTP(config.SMTP_HOST, config.SMTP_PORT)
+ #登录邮箱
+ con.login(config.SMTP_USER, config.SMTP_PASSWORD)
+
+ # 准备数据 创建邮件对象
+ msg = MIMEMultipart()
+
+ # 设置邮件主题 设置邮件发送者 设置邮件接受者
+ subject_and_sender=get_subject(text)
+ subject = Header(subject_and_sender, 'utf-8').encode()
+ msg['Subject'] = subject
+ msg['From'] = (f"{subject_and_sender} <{config.SMTP_USER}>")
+ msg['To'] = config.user_email
+
+ # 添加文字内容
+ text = MIMEText(text, 'plain', 'utf-8')
+ msg.attach(text)
+
+ # 发送邮件
+ con.sendmail(config.SMTP_USER,config.user_email, msg.as_string())
+ con.quit()
+
+
+
+
+
+if __name__ == '__main__':
+ config.loads('../conf/config.json')
+ send_email("卖单成交")
+
+
diff --git a/utils/utility.py b/utils/utility.py
new file mode 100644
index 0000000..9c5fbc7
--- /dev/null
+++ b/utils/utility.py
@@ -0,0 +1,110 @@
+import json
+from pathlib import Path
+from decimal import Decimal
+from utils import dingding, smtp
+import datetime
+import time
+import pytz
+
+def as_num(x):
+ # 32f表示保留32位小数点的float型
+ y = '{:.32f}'.format(x)
+ return(y)
+
+
+def get_current_timestamp():
+ """
+ 获取系统的时间.
+ :return:
+ """
+ return int(time.time() * 1000)
+
+def alert(msg):
+ print(msg)
+ dingding.dingding_at_me(msg)
+ smtp.send_email(msg)
+
+def cn_time():
+ """
+ chinese time
+ https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+ """
+ return datetime.datetime.now(pytz.timezone('Asia/Shanghai'))
+
+
+def _get_trader_dir(temp_name: str):
+ """
+ Get path where trader is running in.
+ """
+ cwd = Path.cwd()
+ temp_path = cwd.joinpath(temp_name)
+
+ if temp_path.exists():
+ return cwd, temp_path
+
+ if not temp_path.exists():
+ temp_path.mkdir()
+
+ return cwd, temp_path
+
+
+TRADER_DIR, TEMP_DIR = _get_trader_dir("trader")
+
+
+def get_file_path(filename: str):
+ """
+ Get path for temp file with filename.
+ """
+ return TEMP_DIR.joinpath(filename)
+
+
+def get_folder_path(folder_name: str):
+ """
+ Get path for temp folder with folder name.
+ """
+ folder_path = TEMP_DIR.joinpath(folder_name)
+ if not folder_path.exists():
+ folder_path.mkdir()
+ return folder_path
+
+def load_json(filename: str):
+ """
+ Load data from json file in temp path.
+ """
+ filepath = get_file_path(filename)
+
+ if filepath.exists():
+ with open(filepath, mode="r", encoding="UTF-8") as f:
+ data = json.load(f)
+ return data
+ else:
+ save_json(filename, {})
+ return {}
+
+
+def save_json(filename: str, data: dict):
+ """
+ Save data into json file in temp path.
+ """
+ filepath = get_file_path(filename)
+ with open(filepath, mode="w+", encoding="UTF-8") as f:
+ json.dump(
+ data,
+ f,
+ indent=4,
+ ensure_ascii=False
+ )
+
+
+def round_to(value: float, target: float) -> float:
+ """
+ Round price to price tick value.
+ """
+ value = Decimal(str(value))
+ target = Decimal(str(target))
+ #round() 方法返回浮点数x的四舍五入值。
+ ##eg:
+ ## quantity = round_to(float(config.quantity), float(config.min_qty))
+ rounded = float(int(round(value / target)) * target)
+ return rounded
+