├── max ├── __init__.py ├── helpers.py ├── constants.py └── client.py ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── LICENSE ├── .gitignore ├── README.md └── examples └── all_api_endpoints.py /max/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | An unofficial Python wrapper for the MAX exchange API v2 3 | """ 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # github: kulisu 2 | custom: https://max.maicoin.com/signup?r=ecc3b0ab 3 | -------------------------------------------------------------------------------- /max/helpers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from time import time as _time 4 | 5 | 6 | def get_current_timestamp(): 7 | return int(round(_time() * 1000)) 8 | -------------------------------------------------------------------------------- /max/constants.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | PUBLIC_API_URL = 'https://max-api.maicoin.com/api' 4 | PRIVATE_API_URL = 'https://max-api.maicoin.com/api' 5 | 6 | PUBLIC_API_VERSION = 'v2' 7 | PRIVATE_API_VERSION = 'v2' 8 | 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Description** 11 | A clear and concise description of what the bug is. 12 | 13 | **Reproduction** 14 | 1. Run '...' 15 | 2. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Running details** 21 | - Relevant console output 22 | ```[if any]``` 23 | - Exception traceback 24 | ```[if any]``` 25 | 26 | **Running environment** 27 | - Operating system: [e.g. Microsoft Windows 10] 28 | - Python version: [e.g. 3.6.7] 29 | 30 | **Screenshots** 31 | If applicable, add screenshots to help explain your problem. 32 | 33 | **Additional context** 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Chris Lin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | 3 | # No API key leaks :P 4 | lib/config/ 5 | 6 | ### macOS template 7 | # General 8 | .DS_Store 9 | .AppleDouble 10 | .LSOverride 11 | 12 | # Icon must end with two \r 13 | Icon 14 | 15 | # Thumbnails 16 | ._* 17 | 18 | # Files that might appear in the root of a volume 19 | .DocumentRevisions-V100 20 | .fseventsd 21 | .Spotlight-V100 22 | .TemporaryItems 23 | .Trashes 24 | .VolumeIcon.icns 25 | .com.apple.timemachine.donotpresent 26 | 27 | # Directories potentially created on remote AFP share 28 | .AppleDB 29 | .AppleDesktop 30 | Network Trash Folder 31 | Temporary Items 32 | .apdisk 33 | 34 | ### Python template 35 | # Byte-compiled / optimized / DLL files 36 | __pycache__/ 37 | *.py[cod] 38 | *$py.class 39 | 40 | # C extensions 41 | *.so 42 | 43 | # Distribution / packaging 44 | .Python 45 | build/ 46 | develop-eggs/ 47 | dist/ 48 | downloads/ 49 | eggs/ 50 | .eggs/ 51 | lib64/ 52 | parts/ 53 | sdist/ 54 | var/ 55 | wheels/ 56 | *.egg-info/ 57 | .installed.cfg 58 | *.egg 59 | MANIFEST 60 | 61 | # PyInstaller 62 | # Usually these files are written by a python script from a template 63 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 64 | *.manifest 65 | *.spec 66 | 67 | # Installer logs 68 | pip-log.txt 69 | pip-delete-this-directory.txt 70 | 71 | # Unit test / coverage reports 72 | htmlcov/ 73 | .tox/ 74 | .coverage 75 | .coverage.* 76 | .cache 77 | nosetests.xml 78 | coverage.xml 79 | *.cover 80 | .hypothesis/ 81 | .pytest_cache/ 82 | 83 | # Translations 84 | *.mo 85 | *.pot 86 | 87 | # Django stuff: 88 | *.log 89 | local_settings.py 90 | db.sqlite3 91 | 92 | # Flask stuff: 93 | instance/ 94 | .webassets-cache 95 | 96 | # Scrapy stuff: 97 | .scrapy 98 | 99 | # Sphinx documentation 100 | docs/_build/ 101 | 102 | # PyBuilder 103 | target/ 104 | 105 | # Jupyter Notebook 106 | .ipynb_checkpoints 107 | 108 | # pyenv 109 | .python-version 110 | 111 | # celery beat schedule file 112 | celerybeat-schedule 113 | 114 | # SageMath parsed files 115 | *.sage.py 116 | 117 | # Environments 118 | .env 119 | .venv 120 | env/ 121 | venv/ 122 | ENV/ 123 | env.bak/ 124 | venv.bak/ 125 | 126 | # Spyder project settings 127 | .spyderproject 128 | .spyproject 129 | 130 | # Rope project settings 131 | .ropeproject 132 | 133 | # mkdocs documentation 134 | /site 135 | 136 | # mypy 137 | .mypy_cache/ 138 | 139 | ### Vim template 140 | # Swap 141 | [._]*.s[a-v][a-z] 142 | [._]*.sw[a-p] 143 | [._]s[a-v][a-z] 144 | [._]sw[a-p] 145 | 146 | # Session 147 | Session.vim 148 | 149 | # Temporary 150 | .netrwhist 151 | *~ 152 | 153 | # Auto-generated tag files 154 | tags 155 | 156 | # Persistent undo 157 | [._]*.un~ 158 | 159 | # IntelliJ project files 160 | .idea 161 | *.iml 162 | out 163 | gen 164 | 165 | ### Linux template 166 | # temporary files which can be created if a process still has a handle open of a deleted file 167 | .fuse_hidden* 168 | 169 | # KDE directory preferences 170 | .directory 171 | 172 | # Linux trash folder which might appear on any partition or disk 173 | .Trash-* 174 | 175 | # .nfs files are created when an open file is removed but is still being accessed 176 | .nfs* 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # max-exchange-api-python3 2 | 3 | ## Warning 4 | 5 | This is an UNOFFICIAL wrapper for MAX exchange [HTTP API v2](https://max.maicoin.com/documents/api) written in Python 3.6 6 | 7 | And this wrapper does not receive active maintainance, plaese consider using [CCXT](https://github.com/TaopaiC/ccxt/blob/max-191223/python/ccxt/max.py) 8 | 9 | **USE THIS WRAPPER AT YOUR OWN RISK, I WILL NOT CORRESPOND TO ANY LOSES** 10 | 11 | ## Features 12 | 13 | - Implementation of all [public](https://max.maicoin.com/documents/api_list#/public) and [private](https://max.maicoin.com/documents/api_list#/private) endpoints 14 | - Simple handling of [authentication](https://max.maicoin.com/documents/api_v2#sign) with API key and secret 15 | - All HTTP raw requests and responses can be found [here](https://gist.github.com/kulisu/8e519e2746a394401272a5f1f779c257) 16 | 17 | ## Usage 18 | 19 | 1. [Register an account](https://max.maicoin.com/signup?r=ecc3b0ab) with MAX exchange _(referral link)_ 20 | 2. [Generate API key and secret](https://max.maicoin.com/api_tokens), assign relevant permissions to it 21 | 3. Clone this repository, and run `examples/all_api_endpoints.py` 22 | 4. Write your own trading strategies and get profits ! 23 | 24 | ### Linux 25 | 26 | ```bash 27 | cd ~/ && git clone https://github.com/kulisu/max-exchange-api-python3 28 | cd ~/max-exchange-api-python3 && cp examples/all_api_endpoints.py . 29 | 30 | # update API key and secret 31 | # vim all_api_endpoints.py 32 | 33 | python3 all_api_endpoints.py 34 | ``` 35 | 36 | ### Windows 37 | 38 | ```batch 39 | cd %USERPROFILE%\Downloads 40 | git clone https://github.com/kulisu/max-exchange-api-python3 41 | 42 | cd max-exchange-api-python3 && copy examples\all_api_endpoints.py . 43 | 44 | # update API key and secret 45 | # notepad all_api_endpoints.py 46 | 47 | python3 all_api_endpoints.py 48 | ``` 49 | 50 | ### Example 51 | 52 | ```python 53 | #!/usr/bin/env python3 54 | 55 | from max.client import Client 56 | 57 | if __name__ == '__main__': 58 | client = Client('PUY_MY_API_KEY_HERE', 'PUY_MY_API_SECRET_HERE') 59 | 60 | try: 61 | # Public (Read) 62 | result = client.get_public_all_currencies() 63 | print(f"[I] Invoked get_public_all_currencies() API Result: \n {result}\n") 64 | 65 | result = client.get_public_k_line('maxtwd', 2, 60) 66 | print(f"[I] Invoked get_public_k_line('maxtwd', 2, 60) API Result: \n {result}\n") 67 | 68 | result = client.get_public_pair_depth('maxtwd', 2) 69 | print(f"[I] Invoked get_public_pair_depth('maxtwd', 2) API Result: \n {result}\n") 70 | 71 | result = client.get_public_server_time() 72 | print(f"[I] Invoked get_public_server_time() API Result: \n {result}\n") 73 | 74 | result = client.get_public_withdrawal_constraints() 75 | print(f"[I] Invoked get_public_withdrawal_constraints() API Result: \n {result}\n") 76 | 77 | # Private (Read) 78 | result = client.get_private_account_balances() 79 | print(f"[I] Invoked get_private_account_balances() API Result: \n {result}\n") 80 | 81 | result = client.get_private_deposit_history() 82 | print(f"[I] Invoked get_private_deposit_history() API Result: \n {result}\n") 83 | 84 | result = client.get_private_max_rewards() 85 | print(f"[I] Invoked get_private_max_rewards() API Result: \n {result}\n") 86 | 87 | result = client.get_private_member_profile() 88 | print(f"[I] Invoked get_private_member_profile() API Result: \n {result}\n") 89 | 90 | result = client.get_private_order_history('maxtwd', ['cancel', 'wait', 'done']) 91 | print(f"[I] Invoked get_private_order_history('maxtwd', ['cancel', .., 'done']) API Result: \n {result}\n") 92 | 93 | result = client.get_private_reward_history() 94 | print(f"[I] Invoked get_private_reward_history() API Result: \n {result}\n") 95 | 96 | result = client.get_private_trade_history('maxtwd') 97 | print(f"[I] Invoked get_private_trade_history('maxtwd') API Result: \n {result}\n") 98 | 99 | result = client.get_private_transfer_history() 100 | print(f"[I] Invoked get_private_transfer_history() API Result: \n {result}\n") 101 | 102 | result = client.get_private_withdrawal_history() 103 | print(f"[I] Invoked get_private_withdrawal_history() API Result: \n {result}\n") 104 | except Exception as error: 105 | print(f"[X] {str(error)}") 106 | 107 | # Networking errors occurred here 108 | response = getattr(error, 'read', None) 109 | if callable(response): 110 | print(f"[X] {response().decode('utf-8')}") 111 | ``` 112 | 113 | ## Donation 114 | 115 | If you feel this wrapper saved your times, buy me a coffee ? 116 | 117 | - BTC: 32awSDjEY8V3KYS3bazLjSsu6SB3JiQcDi 118 | - ETH: 0xAC2a7571EBA8986e4Ec9bA1A81Cde323c959c614 119 | - LTC: 3CAJbZ2RbHa2xGtTD42qs3ZDFfHhMM7mF8 120 | - MAX: 0xAC2a7571EBA8986e4Ec9bA1A81Cde323c959c614 121 | - USDT: 34yVszuBhejsbSfnULK187srAhGkoeWgL6 122 | -------------------------------------------------------------------------------- /examples/all_api_endpoints.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from max.client import Client 4 | 5 | if __name__ == '__main__': 6 | client = Client('PUY_MY_API_KEY_HERE', 'PUY_MY_API_SECRET_HERE') 7 | 8 | try: 9 | ''' Public (Read) ''' 10 | result = client.get_public_all_currencies() 11 | print(f"[I] Invoked get_public_all_currencies() API Result: \n {result}\n") 12 | 13 | result = client.get_public_k_line('maxtwd', 2, 60) 14 | print(f"[I] Invoked get_public_k_line('maxtwd', 2, 60) API Result: \n {result}\n") 15 | 16 | result = client.get_public_pair_depth('maxtwd', 2) 17 | print(f"[I] Invoked get_public_pair_depth('maxtwd', 2) API Result: \n {result}\n") 18 | 19 | result = client.get_public_server_time() 20 | print(f"[I] Invoked get_public_server_time() API Result: \n {result}\n") 21 | 22 | result = client.get_public_withdrawal_constraints() 23 | print(f"[I] Invoked get_public_withdrawal_constraints() API Result: \n {result}\n") 24 | 25 | # result = client.get_public_all_markets() 26 | # print(f"[I] Invoked get_public_all_markets() API Result: \n {result}\n") 27 | 28 | # result = client.get_public_all_tickers() 29 | # print(f"[I] Invoked get_public_all_tickers() API Result: \n {result}\n") 30 | 31 | # result = client.get_public_all_tickers('maxtwd') 32 | # print(f"[I] Invoked get_public_all_tickers('maxtwd') API Result: \n {result}\n") 33 | 34 | # result = client.get_public_k_line('maxtwd') 35 | # print(f"[I] Invoked get_public_k_line('maxtwd') API Result: \n {result}\n") 36 | 37 | # result = client.get_public_k_line('maxtwd', 1) 38 | # print(f"[I] Invoked get_public_k_line('maxtwd', 1) API Result: \n {result}\n") 39 | 40 | # result = client.get_public_k_line('maxtwd', 2, 60, 1560502801) 41 | # print(f"[I] Invoked get_public_k_line('maxtwd', 2, 60, 1560502801) API Result: \n {result}\n") 42 | 43 | # result = client.get_public_order_book('maxtwd') 44 | # print(f"[I] Invoked get_public_order_book('maxtwd') API Result: \n {result}\n") 45 | 46 | # result = client.get_public_order_book('maxtwd', 1, 2) 47 | # print(f"[I] Invoked get_public_order_book('maxtwd', 1, 2) API Result: \n {result}\n") 48 | 49 | # result = client.get_public_pair_depth('maxtwd') 50 | # print(f"[I] Invoked get_public_pair_depth('maxtwd') API Result: \n {result}\n") 51 | 52 | # result = client.get_public_recent_trades('maxtwd') 53 | # print(f"[I] Invoked get_public_recent_trades('maxtwd') API Result: \n {result}\n") 54 | 55 | # result = client.get_public_recent_trades('maxtwd', 1560509180) 56 | # print(f"[I] Invoked get_public_recent_trades('maxtwd', 1560509180) API Result: \n {result}\n") 57 | 58 | ''' Private (Read) ''' 59 | result = client.get_private_account_balances() 60 | print(f"[I] Invoked get_private_account_balances() API Result: \n {result}\n") 61 | 62 | result = client.get_private_deposit_history() 63 | print(f"[I] Invoked get_private_deposit_history() API Result: \n {result}\n") 64 | 65 | result = client.get_private_max_rewards() 66 | print(f"[I] Invoked get_private_max_rewards() API Result: \n {result}\n") 67 | 68 | result = client.get_private_member_profile() 69 | print(f"[I] Invoked get_private_member_profile() API Result: \n {result}\n") 70 | 71 | result = client.get_private_order_history('maxtwd', ['cancel', 'wait', 'done']) 72 | print(f"[I] Invoked get_private_order_history('maxtwd', ['cancel', .., 'done']) API Result: \n {result}\n") 73 | 74 | result = client.get_private_reward_history() 75 | print(f"[I] Invoked get_private_reward_history() API Result: \n {result}\n") 76 | 77 | result = client.get_private_trade_history('maxtwd') 78 | print(f"[I] Invoked get_private_trade_history('maxtwd') API Result: \n {result}\n") 79 | 80 | result = client.get_private_transfer_history(side='out') 81 | print(f"[I] Invoked get_private_transfer_history(side='out') API Result: \n {result}\n") 82 | 83 | result = client.get_private_withdrawal_history() 84 | print(f"[I] Invoked get_private_withdrawal_history() API Result: \n {result}\n") 85 | 86 | # result = client.get_private_account_balance('max') 87 | # print(f"[I] Invoked get_private_account_balance('max') API Result: \n {result}\n") 88 | 89 | # result = client.get_private_deposit_address() 90 | # print(f"[I] Invoked get_private_deposit_address() API Result: \n {result}\n") 91 | 92 | # result = client.get_private_deposit_address('max') 93 | # print(f"[I] Invoked get_private_deposit_address('max') API Result: \n {result}\n") 94 | 95 | # result = client.get_private_deposit_addresses() 96 | # print(f"[I] Invoked get_private_deposit_addresses() API Result: \n {result}\n") 97 | 98 | # result = client.get_private_deposit_addresses('max') 99 | # print(f"[I] Invoked get_private_deposit_addresses('max') API Result: \n {result}\n") 100 | 101 | # result = client.get_private_deposit_detail('0x0123456789abcdef..') 102 | # print(f"[I] Invoked get_private_deposit_detail('0x0123456789abcdef..') API Result: \n {result}\n") 103 | 104 | # result = client.get_private_deposit_history('usdt') 105 | # print(f"[I] Invoked get_private_deposit_history('usdt') API Result: \n {result}\n") 106 | 107 | # result = client.get_private_deposit_history('usdt', state='accepted') 108 | # print(f"[I] Invoked get_private_deposit_history('usdt', state='accepted') API Result: \n {result}\n") 109 | 110 | # result = client.get_private_executed_trades(12345678) 111 | # print(f"[I] Invoked get_private_executed_trades(12345678) API Result: \n {result}\n") 112 | 113 | # result = client.get_private_member_me() 114 | # print(f"[I] Invoked get_private_member_me() API Result: \n {result}\n") 115 | 116 | # result = client.get_private_order_detail(12345678) 117 | # print(f"[I] Invoked get_private_order_detail(12345678) API Result: \n {result}\n") 118 | 119 | # result = client.get_private_order_history('maxtwd') 120 | # print(f"[I] Invoked get_private_order_history('maxtwd') API Result: \n {result}\n") 121 | 122 | # result = client.get_private_reward_history('max', _type='holding') 123 | # print(f"[I] Invoked get_private_reward_history('max', _type='holding') API Result: \n {result}\n") 124 | 125 | # result = client.get_private_transfer_detail(12345678901234567) 126 | # print(f"[I] Invoked get_private_transfer_detail(12345678901234567) API Result: \n {result}\n") 127 | 128 | # result = client.get_private_transfer_history('max', side='out') 129 | # print(f"[I] Invoked get_private_transfer_history('max', side='out') API Result: \n {result}\n") 130 | 131 | # result = client.get_private_withdrawal_addresses('usdt') 132 | # print(f"[I] Invoked get_private_withdrawal_addresses('usdt') API Result: \n {result}\n") 133 | 134 | # result = client.get_private_withdrawal_detail(1234567890123456) 135 | # print(f"[I] Invoked get_private_withdrawal_detail(1234567890123456) API Result: \n {result}\n") 136 | 137 | ''' Private (Write) ''' 138 | # result = client.set_private_cancel_order(12345678) 139 | # print(f"[I] Invoked set_private_cancel_order(12345678) API Result: \n {result}\n") 140 | 141 | # result = client.set_private_cancel_orders('maxtwd', 'sell') 142 | # print(f"[I] Invoked set_private_cancel_orders('maxtwd', 'sell') API Result: \n {result}\n") 143 | 144 | # result = client.set_private_create_order('maxtwd', 'sell', 100, 123456) 145 | # print(f"[I] Invoked set_private_create_order('maxtwd', 'sell', 100, 123456) API Result: \n {result}\n") 146 | 147 | """ 148 | result = client.set_private_create_orders( 149 | 'maxtwd', ['sell', 'sell'], [100, 100], [999, 999], _types=['limit', 'limit'] 150 | ) 151 | print(f"[I] Invoked set_private_create_orders('maxtwd', ['sell', 'sell'], ..) API Result: \n {result}\n") 152 | """ 153 | 154 | # result = client.set_private_deposit_address('xrp') 155 | # print(f"[I] Invoked set_private_deposit_address('xrp') API Result: \n {result}\n") 156 | except Exception as error: 157 | print(f"[X] Exception: {str(error)}") 158 | 159 | # Networking errors occurred here 160 | response = getattr(error, 'read', None) 161 | if callable(response): 162 | print(f"[X] Reason: {response().decode('utf-8')}") 163 | -------------------------------------------------------------------------------- /max/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import base64 4 | import hashlib 5 | import hmac 6 | import json 7 | 8 | from urllib.parse import urlencode 9 | from urllib.request import Request 10 | from urllib.request import urlopen 11 | 12 | from .constants import * 13 | from .helpers import * 14 | 15 | 16 | class Client(object): 17 | def __init__(self, key, secret, timeout=30): 18 | self._api_key = key 19 | self._api_secret = secret 20 | 21 | self._api_timeout = int(timeout) 22 | 23 | def _build_body(self, endpoint, query=None): 24 | if query is None: 25 | query = {} 26 | 27 | # TODO: duplicated nonce may occurred in high frequency trading 28 | # fix it by yourself, hard code last two characters is a quick solution 29 | # {"error":{"code":2006,"message":"The nonce has already been used by access key."}} 30 | body = { 31 | 'path': f"/api/{PRIVATE_API_VERSION}/{endpoint}.json", 32 | 'nonce': get_current_timestamp(), 33 | } 34 | 35 | body.update(query) 36 | 37 | return body 38 | 39 | def _build_headers(self, scope, body=None): 40 | if body is None: 41 | body = {} 42 | 43 | headers = { 44 | 'Accept': 'application/json', 45 | 'User-Agent': 'pyCryptoTrader/1.0.3', 46 | } 47 | 48 | if scope.lower() == 'private': 49 | payload = self._build_payload(body) 50 | sign = hmac.new(bytes(self._api_secret, 'utf-8'), bytes(payload, 'utf-8'), hashlib.sha256).hexdigest() 51 | 52 | headers.update({ 53 | # This header is REQUIRED to send JSON data. 54 | # or you have to send PLAIN form data instead. 55 | 'Content-Type': 'application/json', 56 | 'X-MAX-ACCESSKEY': self._api_key, 57 | 'X-MAX-PAYLOAD': payload, 58 | 'X-MAX-SIGNATURE': sign 59 | }) 60 | 61 | return headers 62 | 63 | def _build_payload(self, body): 64 | return base64.urlsafe_b64encode(json.dumps(body).encode('utf-8')).decode('utf-8') 65 | 66 | def _build_url(self, scope, endpoint, body=None, query=None): 67 | if query is None: 68 | query = {} 69 | 70 | if body is None: 71 | body = {} 72 | 73 | # 2020-03-03 Updated 74 | # All query parameters must equal to payload 75 | query.update(body) 76 | 77 | if scope.lower() == 'private': 78 | url = f"{PRIVATE_API_URL}/{PRIVATE_API_VERSION}/{endpoint}.json" 79 | else: 80 | url = f"{PUBLIC_API_URL}/{PUBLIC_API_VERSION}/{endpoint}.json" 81 | 82 | return f"{url}?{urlencode(query, True, '/[]')}" if len(query) > 0 else url 83 | 84 | def _send_request(self, scope, method, endpoint, query=None, form=None): 85 | if form is None: 86 | form = {} 87 | 88 | if query is None: 89 | query = {} 90 | 91 | body = self._build_body(endpoint, query) 92 | data = None 93 | 94 | if len(form) > 0: 95 | body.update(form) 96 | data = json.dumps(body).encode('utf-8') 97 | 98 | # Build X-MAX-PAYLOAD header first 99 | headers = self._build_headers(scope, body) 100 | 101 | # Fix "401 Payload is not consistent .." 102 | # state[]=cancel&state[]=wait&state[]=done 103 | # {"path": "/api/v2/orders.json", "state": ["cancel", "wait", "done"]} 104 | for key in body: 105 | if type(body[key]) is list and not key[-2:] == '[]': 106 | body[f"{key}[]"] = body.pop(key) 107 | 108 | if key in query: 109 | query.pop(key) 110 | 111 | # Build final url here 112 | url = self._build_url(scope, endpoint, body, query) 113 | 114 | request = Request(headers=headers, method=method.upper(), url=url.lower()) 115 | 116 | # Start: Debugging with BurpSuite only 117 | # import ssl 118 | # ssl._create_default_https_context = ssl._create_unverified_context 119 | 120 | """ 121 | root@kali:/tmp/max-exchange-api-python3# export HTTPS_PROXY=https://127.0.0.1:8080 122 | root@kali:/tmp/max-exchange-api-python3# /usr/bin/python3 all_api_endpoints.py 123 | """ 124 | # End: Debugging with BurpSuite only 125 | 126 | response = urlopen(request, data=data, timeout=self._api_timeout) 127 | 128 | return json.loads(response.read()) 129 | 130 | # Public API 131 | def get_public_all_currencies(self): 132 | """ 133 | https://max.maicoin.com/documents/api_list#!/public/getApiV2Currencies 134 | 135 | :return: a list contains all available currencies 136 | """ 137 | 138 | return self._send_request('public', 'GET', 'currencies') 139 | 140 | def get_public_all_markets(self): 141 | """ma 142 | https://max.maicoin.com/documents/api_list#!/public/getApiV2Markets 143 | 144 | :return: a list contains all available markets 145 | """ 146 | 147 | return self._send_request('public', 'GET', 'markets') 148 | 149 | def get_public_all_tickers(self, pair=None): 150 | """ 151 | https://max.maicoin.com/documents/api_list#!/public/getApiV2Tickers 152 | 153 | :param pair: the specific trading pair to query (optional) 154 | :return: a list contains all pair tickers 155 | """ 156 | 157 | if pair is not None and len(pair) > 0: 158 | return self._send_request('public', 'GET', f"tickers/{pair.lower()}") 159 | else: 160 | return self._send_request('public', 'GET', 'tickers') 161 | 162 | def get_public_k_line(self, pair, limit=30, period=1, timestamp=''): 163 | """ 164 | https://max.maicoin.com/documents/api_list#!/public/getApiV2K 165 | 166 | :param pair: the trading pair to query 167 | :param limit: the data points limit to query 168 | :param period: the time period of K line in minute 169 | :param timestamp: the Unix epoch seconds set to return trades executed before the time only 170 | :return: a list contains all OHLC prices in exchange 171 | """ 172 | 173 | query = { 174 | 'market': pair.lower(), 175 | 'limit': limit, 176 | 'period': period, 177 | 'timestamp': timestamp 178 | } 179 | 180 | return self._send_request('public', 'GET', 'k', query) 181 | 182 | def get_public_markets_summary(self): 183 | """ 184 | https://max.maicoin.com/documents/api_list#!/public/getApiV2Summary 185 | 186 | :return: a dict contains overview of market data for all tickers 187 | """ 188 | 189 | return self._send_request('public', 'GET', 'summary') 190 | 191 | # TODO: this is a deprecated endpoint 192 | def get_public_order_book(self, pair, asks=20, bids=20): 193 | """ 194 | https://max.maicoin.com/documents/api_list#!/public/getApiV2OrderBook 195 | 196 | :param pair: the trading pair to query 197 | :param asks: the sell orders limit to query 198 | :param bids: the buy orders limit to query 199 | :return: a dict contains asks and bids data 200 | """ 201 | 202 | raise DeprecationWarning('this route will be removed since 2021/5/30, please use api/v2/depth to instead.') 203 | 204 | query = { 205 | 'market': pair.lower(), 206 | 'asks_limit': asks, 207 | 'bids_limit': bids 208 | } 209 | 210 | return self._send_request('public', 'GET', 'order_book', query) 211 | 212 | def get_public_pair_depth(self, pair, limit=300): 213 | """ 214 | https://max.maicoin.com/documents/api_list#!/public/getApiV2Depth 215 | 216 | :param pair: the trading pair to query 217 | :param limit: the price levels limit to query 218 | :return: a dict contains asks and bids data 219 | """ 220 | 221 | query = { 222 | 'market': pair.lower(), 223 | 'limit': limit 224 | } 225 | 226 | return self._send_request('public', 'GET', 'depth', query) 227 | 228 | def get_public_recent_trades(self, pair, timestamp='', _from='', 229 | to='', sort='desc', pagination=True, 230 | page=1, limit=50, offset=0): 231 | """ 232 | https://max.maicoin.com/documents/api_list#!/public/getApiV2Trades 233 | 234 | :param pair: the trading pair to query 235 | :param timestamp: the Unix epoch seconds set to return trades executed before the time only 236 | :param _from: the order id set to return trades created after the trade 237 | :param to: the order id set to return trades created before the trade 238 | :param sort: sort the trades by created time, default is 'desc' 239 | :param pagination: do pagination and return metadata in header 240 | :param page: the page number applied for pagination 241 | :param limit: the records limit to query 242 | :param offset: the records to skip, not applied for pagination 243 | :return: a list contains all completed orders in exchange 244 | """ 245 | 246 | query = { 247 | 'market': pair.lower(), 248 | 'timestamp': timestamp, 249 | 'from': _from, 250 | 'to': to, 251 | 'order_by': sort, 252 | 'pagination': pagination, 253 | 'page': page, 254 | 'limit': limit, 255 | 'offset': offset 256 | } 257 | 258 | return self._send_request('public', 'GET', 'trades', query) 259 | 260 | def get_public_server_time(self): 261 | """ 262 | https://max.maicoin.com/documents/api_list#!/public/getApiV2Timestamp 263 | 264 | :return: an integer in seconds since Unix epoch of server's current time 265 | """ 266 | 267 | return self._send_request('public', 'GET', 'timestamp') 268 | 269 | def get_public_withdrawal_constraints(self): 270 | """ 271 | https://max.maicoin.com/documents/api_list#!/public/getApiV2WithdrawalConstraint 272 | 273 | :return: a list contains all withdrawal constraints 274 | """ 275 | 276 | return self._send_request('public', 'GET', 'withdrawal/constraint') 277 | 278 | def get_public_vip_levels(self, level=None): 279 | """ 280 | https://max.maicoin.com/documents/api_list#!/public/getApiV2VipLevels 281 | 282 | :param level: the specific VIP level to query (optional) 283 | :return: a list contains all VIP level fees 284 | """ 285 | 286 | if level is not None and type(level) is int: 287 | return self._send_request('public', 'GET', f"vip_levels/{level}") 288 | else: 289 | return self._send_request('public', 'GET', 'vip_levels') 290 | 291 | # Private API (Read) 292 | def get_private_account_balance(self, currency): 293 | """ 294 | https://max.maicoin.com/documents/api_list#!/private/getApiV2MembersAccountsCurrency 295 | 296 | :param currency: the specific coin to query 297 | :return: a dict contains all balance information 298 | """ 299 | 300 | return self._send_request('private', 'GET', f"members/accounts/{currency.lower()}") 301 | 302 | def get_private_account_balances(self): 303 | """ 304 | https://max.maicoin.com/documents/api_list#!/private/getApiV2MembersAccounts 305 | 306 | :return: a list contains all coins balance 307 | """ 308 | 309 | return self._send_request('private', 'GET', 'members/accounts') 310 | 311 | # TODO: this is a deprecated endpoint 312 | def get_private_deposit_address(self, currency=''): 313 | """ 314 | https://max.maicoin.com/documents/api_list#!/private/getApiV2DepositAddress 315 | 316 | :param currency: the specific coin to query 317 | :return: a list contains all deposit addresses 318 | """ 319 | 320 | query = {} 321 | 322 | if currency is not None and len(currency) > 0: 323 | query['currency'] = currency.lower() 324 | 325 | return self._send_request('private', 'GET', 'deposit_address', query) 326 | 327 | def get_private_deposit_addresses(self, currency=''): 328 | """ 329 | https://max.maicoin.com/documents/api_list#!/private/getApiV2DepositAddresses 330 | 331 | :param currency: the specific coin to query 332 | :return: a list contains all deposit addresses 333 | """ 334 | 335 | query = {} 336 | 337 | if currency is not None and len(currency) > 0: 338 | query['currency'] = currency.lower() 339 | 340 | return self._send_request('private', 'GET', 'deposit_addresses', query) 341 | 342 | def get_private_deposit_detail(self, _id): 343 | """ 344 | https://max.maicoin.com/documents/api_list#!/private/getApiV2Deposit 345 | 346 | :param _id: the specific tx ID to query 347 | :return: a dict contains all deposit information 348 | """ 349 | 350 | return self._send_request('private', 'GET', 'deposit', {'txid': _id}) 351 | 352 | def get_private_deposit_history(self, currency='', _from='', to='', state='', 353 | pagination=False, page=1, limit=50, offset=0): 354 | """ 355 | https://max.maicoin.com/documents/api_list#!/private/getApiV2Deposits 356 | 357 | :param currency: the specific coin to query 358 | :param _from: the target period after Epoch time in seconds 359 | :param to: the target period before Epoch time in seconds 360 | :param state: the deposits status to query 361 | :param pagination: do pagination and return metadata in header 362 | :param page: the page number applied for pagination 363 | :param limit: the records limit to query 364 | :param offset: the records to skip, not applied for pagination 365 | :return: a list contains all completed deposits in exchange 366 | """ 367 | 368 | query = { 369 | 'from': _from, 370 | 'to': to, 371 | 'pagination': pagination, 372 | 'page': page, 373 | 'limit': limit, 374 | 'offset': offset 375 | } 376 | 377 | if currency is not None and len(currency) > 0: 378 | query['currency'] = currency.lower() 379 | if state is not None and len(state) > 0: 380 | query['state'] = state.lower() 381 | 382 | return self._send_request('private', 'GET', 'deposits', query) 383 | 384 | def get_private_executed_trades(self, _id): 385 | """ 386 | https://max.maicoin.com/documents/api_list#!/private/getApiV2TradesMyOfOrder 387 | 388 | :param _id: the id of the order 389 | :return: a list contains all trades in an order 390 | """ 391 | 392 | return self._send_request('private', 'GET', 'trades/my/of_order', {'id': _id}) 393 | 394 | def get_private_max_rewards(self): 395 | """ 396 | https://max.maicoin.com/documents/api_list#!/private/getApiV2MaxRewardsYesterday 397 | 398 | :return: a dict contains all MAX rewards in yesterday 399 | """ 400 | 401 | return self._send_request('private', 'GET', 'max_rewards/yesterday') 402 | 403 | def get_private_member_me(self): 404 | """ 405 | https://max.maicoin.com/documents/api_list#!/private/getApiV2MembersMe 406 | 407 | :return: a dict contains all personal profile and balances information 408 | """ 409 | 410 | return self._send_request('private', 'GET', 'members/me') 411 | 412 | def get_private_member_profile(self): 413 | """ 414 | https://max.maicoin.com/documents/api_list#!/private/getApiV2MembersProfile 415 | 416 | :return: a dict contains all personal profile information 417 | """ 418 | 419 | return self._send_request('private', 'GET', 'members/profile') 420 | 421 | def get_private_vip_level(self): 422 | """ 423 | https://max.maicoin.com/documents/api_list#!/private/getApiV2MembersVipLevel 424 | 425 | :return: a dict contains VIP level info 426 | """ 427 | 428 | return self._send_request('private', 'GET', 'members/vip_level') 429 | 430 | def get_private_order_detail(self, _id, client_id=''): 431 | """ 432 | https://max.maicoin.com/documents/api_list#!/private/getApiV2Order 433 | 434 | :param _id: the id of the order 435 | :param client_id: a unique order id specified by user, must less or equal to 36 436 | :return: a dict contains all order information 437 | """ 438 | 439 | if client_id is not None and len(client_id) > 0: 440 | return self._send_request('private', 'GET', 'order', {'client_oid': client_id}) 441 | else: 442 | return self._send_request('private', 'GET', 'order', {'id': _id}) 443 | 444 | def get_private_order_history(self, pair, state=None, sort='asc', pagination=True, 445 | page=1, limit=100, offset=0, group_id=''): 446 | """ 447 | https://max.maicoin.com/documents/api_list#!/private/getApiV2Orders 448 | 449 | :param pair: the trading pair to query 450 | :param state: the states to be filtered, default is 'wait' and 'convert' 451 | :param sort: sort the orders by created time, default is 'asc' 452 | :param pagination: do pagination and return metadata in header 453 | :param page: the page number applied for pagination 454 | :param limit: the orders limit to query 455 | :param offset: the records to skip, not applied for pagination 456 | :param group_id: a integer group id for orders 457 | :return: a list contains all placed orders 458 | """ 459 | 460 | if state is None: 461 | state = ['wait', 'convert'] 462 | 463 | query = { 464 | 'market': pair.lower(), 465 | 'order_by': sort.lower(), 466 | 'pagination': pagination, 467 | 'page': page, 468 | 'limit': limit, 469 | 'offset': offset 470 | 471 | } 472 | 473 | if state is not None and len(state) > 0: 474 | query['state'] = state 475 | 476 | if group_id is not None and type(group_id) is int: 477 | query['group_id'] = group_id 478 | 479 | return self._send_request('private', 'GET', 'orders', query) 480 | 481 | def get_private_reward_history(self, currency='', _from='', to='', _type='', 482 | pagination=False, page=1, limit=50, offset=0): 483 | """ 484 | https://max.maicoin.com/documents/api_list#!/private/getApiV2Rewards 485 | 486 | :param currency: the specific coin to query 487 | :param _from: the target period after Epoch time in seconds 488 | :param to: the target period before Epoch time in seconds 489 | :param _type: the rewards type, should be 'airdrop' or 'holding', 'mining' or 'trading' 490 | :param pagination: do pagination and return metadata in header 491 | :param page: the page number applied for pagination 492 | :param limit: the records limit to query 493 | :param offset: the records to skip, not applied for pagination 494 | :return: a list contains all rewards information 495 | """ 496 | 497 | query = { 498 | 'from': _from, 499 | 'to': to, 500 | 'pagination': pagination, 501 | 'page': page, 502 | 'limit': limit, 503 | 'offset': offset 504 | } 505 | 506 | if currency is not None and len(currency) > 0: 507 | query['currency'] = currency.lower() 508 | 509 | if _type is not None and len(_type) > 0: 510 | return self._send_request('private', 'GET', f"rewards/{_type}_reward", query) 511 | else: 512 | return self._send_request('private', 'GET', 'rewards', query) 513 | 514 | def get_private_trade_history(self, pair, timestamp='', _from='', 515 | to='', sort='desc', pagination=True, 516 | page=1, limit=50, offset=0): 517 | """ 518 | https://max.maicoin.com/documents/api_list#!/private/getApiV2TradesMy 519 | 520 | :param pair: the trading pair to query 521 | :param timestamp: the Unix epoch seconds set to return trades executed before the time only 522 | :param _from: the order id set to return trades created after the trade 523 | :param to: the order id set to return trades created before the trade 524 | :param sort: sort the trades by created time, default is 'desc' 525 | :param pagination: do pagination and return metadata in header 526 | :param page: the page number applied for pagination 527 | :param limit: the records limit to query 528 | :param offset: the records to skip, not applied for pagination 529 | :return: a list contains all completed trades 530 | """ 531 | 532 | query = { 533 | 'market': pair.lower(), 534 | 'timestamp': timestamp, 535 | 'from': _from, 536 | 'to': to, 537 | 'order_by': sort, 538 | 'pagination': pagination, 539 | 'page': page, 540 | 'limit': limit, 541 | 'offset': offset 542 | } 543 | 544 | return self._send_request('private', 'GET', 'trades/my', query) 545 | 546 | def get_private_transfer_detail(self, _id): 547 | """ 548 | https://max.maicoin.com/documents/api_list#!/private/getApiV2InternalTransfer 549 | 550 | :param _id: the internal transfer id to query 551 | :return: a dict contains all transfer information 552 | """ 553 | 554 | return self._send_request('private', 'GET', 'internal_transfer', {'uuid': _id}) 555 | 556 | def get_private_transfer_history(self, currency='', _from='', to='', side='', 557 | pagination=False, page=1, limit=50, offset=0): 558 | """ 559 | https://max.maicoin.com/documents/api_list#!/private/getApiV2InternalTransfers 560 | 561 | :param currency: the specific coin to query 562 | :param _from: the target period after Epoch time in seconds 563 | :param to: the target period before Epoch time in seconds 564 | :param side: the transfer side, should be 'in' or 'out' 565 | :param pagination: do pagination and return metadata in header 566 | :param page: the page number applied for pagination 567 | :param limit: the records limit to query 568 | :param offset: the records to skip, not applied for pagination 569 | :return: a list contains all transferred information 570 | """ 571 | 572 | query = { 573 | 'from': _from, 574 | 'to': to, 575 | 'pagination': pagination, 576 | 'page': page, 577 | 'limit': limit, 578 | 'offset': offset 579 | } 580 | 581 | if currency is not None and len(currency) > 0: 582 | query['currency'] = currency.lower() 583 | if side is not None and len(side) > 0: 584 | query['side'] = side.lower() 585 | 586 | return self._send_request('private', 'GET', 'internal_transfers', query) 587 | 588 | def get_private_withdrawal_addresses(self, currency, pagination=True, page=1, limit=100, offset=0): 589 | """ 590 | https://max.maicoin.com/documents/api_list#!/private/getApiV2WithdrawAddresses 591 | 592 | :param currency: the specific coin to query 593 | :param pagination: do pagination and return metadata in header 594 | :param page: the page number applied for pagination 595 | :param limit: the records limit to query 596 | :param offset: the records to skip, not applied for pagination 597 | :return: a list contains all withdraw addresses 598 | """ 599 | 600 | query = { 601 | 'currency': currency.lower(), 602 | 'pagination': pagination, 603 | 'page': page, 604 | 'limit': limit, 605 | 'offset': offset 606 | } 607 | 608 | return self._send_request('private', 'GET', 'withdraw_addresses', query) 609 | 610 | def get_private_withdrawal_detail(self, _id): 611 | """ 612 | https://max.maicoin.com/documents/api_list#!/private/getApiV2Withdrawal 613 | 614 | :param _id: the specific withdrawal UUID to query 615 | :return: a dict contains all withdrawal information 616 | """ 617 | 618 | return self._send_request('private', 'GET', 'withdrawal', {'uuid': _id}) 619 | 620 | def get_private_withdrawal_history(self, currency='', _from='', to='', state='', 621 | pagination=False, page=1, limit=50, offset=0): 622 | """ 623 | https://max.maicoin.com/documents/api_list#!/private/getApiV2Withdrawals 624 | 625 | :param currency: the specific coin to query 626 | :param _from: the target period after Epoch time in seconds 627 | :param to: the target period before Epoch time in seconds 628 | :param state: the withdrawals status to query 629 | :param pagination: do pagination and return metadata in header 630 | :param page: the page number applied for pagination 631 | :param limit: the records limit to query 632 | :param offset: the records to skip, not applied for pagination 633 | :return: a list contains all completed withdrawals in exchange 634 | """ 635 | 636 | query = { 637 | 'from': _from, 638 | 'to': to, 639 | 'pagination': pagination, 640 | 'page': page, 641 | 'limit': limit, 642 | 'offset': offset 643 | } 644 | 645 | if currency is not None and len(currency) > 0: 646 | query['currency'] = currency.lower() 647 | if state is not None and len(state) > 0: 648 | query['state'] = state.lower() 649 | 650 | return self._send_request('private', 'GET', 'withdrawals', query) 651 | 652 | # Private API (Write) 653 | def set_private_cancel_order(self, _id, client_id=''): 654 | """ 655 | https://max.maicoin.com/documents/api_list#!/private/postApiV2OrderDelete 656 | 657 | :param _id: the id of the order 658 | :param client_id: a unique order id specified by user, must less or equal to 36 659 | :return: a dict contains cancelled order information 660 | """ 661 | 662 | if client_id is not None and len(client_id) > 0: 663 | return self._send_request('private', 'POST', 'order/delete', {'client_oid': client_id}) 664 | else: 665 | return self._send_request('private', 'POST', 'order/delete', {}, {'id': _id}) 666 | 667 | def set_private_cancel_orders(self, pair='', side='', group_id=''): 668 | """ 669 | https://max.maicoin.com/documents/api_list#!/private/postApiV2OrdersClear 670 | 671 | :param pair: the trading pair to clear all orders 672 | :param side: the trading side to clear all orders 673 | :param group_id: a integer group id for orders 674 | :return: a list contains all cleared orders 675 | """ 676 | 677 | form = {} 678 | 679 | if pair is not None and len(pair) > 0: 680 | form['market'] = pair.lower() 681 | 682 | if side is not None and len(side) > 0: 683 | form['side'] = side.lower() 684 | 685 | if group_id is not None and type(group_id) is int: 686 | form['group_id'] = group_id 687 | 688 | return self._send_request('private', 'POST', 'orders/clear', {}, form) 689 | 690 | def set_private_create_order(self, pair, side, amount, price, stop='', _type='limit', client_id='', group_id=''): 691 | """ 692 | https://max.maicoin.com/documents/api_list#!/private/postApiV2Orders 693 | 694 | :param pair: the trading pair to create 695 | :param side: the trading side, should only be buy or sell 696 | :param amount: the amount of the order for the trading pair 697 | :param price: the price of the order for the trading pair 698 | :param stop; the price to trigger a stop order 699 | :param _type: the order type, should only be limit, market, stop_limit or stop_market 700 | :param client_id: a unique order id specified by user, must less or equal to 36 701 | :param group_id: a integer group id for orders 702 | :return: a dict contains created order information 703 | """ 704 | 705 | form = { 706 | 'market': pair.lower(), 707 | 'side': side.lower(), 708 | 'volume': str(amount), 709 | 'price': str(price), 710 | 'ord_type': _type.lower() 711 | } 712 | 713 | if stop is not None and len(stop) > 0: 714 | form['stop_price'] = str(stop) 715 | 716 | if client_id is not None and len(client_id) > 0: 717 | form['client_oid'] = client_id 718 | 719 | if group_id is not None and type(group_id) is int: 720 | form['group_id'] = group_id 721 | 722 | return self._send_request('private', 'POST', 'orders', {}, form) 723 | 724 | def set_private_create_orders(self, pair, sides=None, amounts=None, prices=None, stops=None, _types=None): 725 | """ 726 | https://max.maicoin.com/documents/api_list#!/private/postApiV2OrdersMulti 727 | 728 | :param pair: the trading pair to create 729 | :param sides: the trading side, should only be buy or sell 730 | :param amounts: the amount of the order for the trading pair 731 | :param prices: the price of the order for the trading pair 732 | :param stops; the price to trigger a stop order 733 | :param _types: the order type, should only be limit, market, stop_limit or stop_market 734 | :return: a list contains created orders information 735 | """ 736 | 737 | raise DeprecationWarning('this route will be removed since 2021/4/30') 738 | 739 | if _types is None: 740 | _types = [] 741 | 742 | if stops is None: 743 | stops = [] 744 | 745 | if prices is None: 746 | prices = [] 747 | 748 | if amounts is None: 749 | amounts = [] 750 | 751 | if sides is None: 752 | sides = [] 753 | 754 | orders = [] 755 | 756 | if type(sides) is not list or type(amounts) is not list or type(prices) is not list: 757 | raise ValueError 758 | if type(stops) is not list or type(_types) is not list or len(_types) == 0: 759 | raise ValueError 760 | 761 | for i in range(0, len(sides)): 762 | orders.append({ 763 | 'side': sides[i].lower(), 764 | 'volume': str(amounts[i]), 765 | 'price': str(prices[i]), 766 | 'ord_type': _types[i].lower() 767 | }) 768 | 769 | return self._send_request('private', 'POST', 'orders/multi', {}, {'market': pair.lower(), 'orders': orders}) 770 | 771 | def set_private_create_withdrawal(self, currency, amount, address): 772 | form = { 773 | 'currency': currency.lower(), 774 | 'withdraw_address_uuid': address, 775 | 'amount': str(amount), 776 | } 777 | 778 | return self._send_request('private', 'POST', 'withdrawal', {}, form) 779 | 780 | def set_private_deposit_address(self, currency): 781 | """ 782 | https://max.maicoin.com/documents/api_list#!/private/postApiV2DepositAddresses 783 | 784 | :param currency: the specific coin to create 785 | :return: a list contains created deposit address 786 | """ 787 | 788 | return self._send_request('private', 'POST', 'deposit_addresses', {}, {'currency': currency.lower()}) 789 | --------------------------------------------------------------------------------