├── .gitignore ├── FIX ├── README.md ├── app │ ├── __init__.py │ ├── configuration.py │ ├── dictionary.py │ ├── fix_session.py │ └── logger.py ├── build_cancel_order.py ├── build_create_order.py ├── build_get_order.py ├── client_cancel_order.py ├── client_create_order.py ├── client_get_order.py └── requirements.txt ├── LICENSE ├── README.md ├── REST ├── README.md ├── prime_cancel_order.py ├── prime_create_address_book_entry.py ├── prime_create_allocations.py ├── prime_create_conversion.py ├── prime_create_order.py ├── prime_create_order_preview.py ├── prime_create_rfq_always_accept.py ├── prime_create_rfq_compare_clob.py ├── prime_create_transfer.py ├── prime_create_wallet.py ├── prime_create_withdrawal.py ├── prime_create_withdrawal_to_payment_method.py ├── prime_get_activity_by_id.py ├── prime_get_allocation_by_id.py ├── prime_get_commission.py ├── prime_get_entity_activity_by_id.py ├── prime_get_net_allocation_by_id.py ├── prime_get_order_by_id.py ├── prime_get_order_fills.py ├── prime_get_portfolio_by_id.py ├── prime_get_portfolio_credit_information.py ├── prime_get_transaction.py ├── prime_get_wallet_balance.py ├── prime_get_wallet_by_id.py ├── prime_get_wallet_by_name.py ├── prime_get_wallet_deposit_instructions.py ├── prime_list_activities.py ├── prime_list_address_book.py ├── prime_list_allocations.py ├── prime_list_assets.py ├── prime_list_balances.py ├── prime_list_balances_csv.py ├── prime_list_entity_activities.py ├── prime_list_entity_payment_methods.py ├── prime_list_fills.py ├── prime_list_invoices.py ├── prime_list_open_orders.py ├── prime_list_orders.py ├── prime_list_payment_methods.py ├── prime_list_portfolios.py ├── prime_list_products.py ├── prime_list_transactions.py ├── prime_list_wallets.py ├── prime_locate_order_by_client_order_id.py ├── prime_ws_heartbeats.py ├── prime_ws_market.py ├── prime_ws_orders.py └── requirements.txt └── THIRD-PARTY-NOTICES /.gitignore: -------------------------------------------------------------------------------- 1 | /shelf/ 2 | /workspace.xml 3 | /httpRequests/ 4 | /dataSources/ 5 | /dataSources.local.xml 6 | .idea 7 | .envrc 8 | .direnv/ 9 | REST/.env 10 | FIX/logs 11 | FIX/sessions 12 | __pycache__/ 13 | *.pyc 14 | *.pyo 15 | FIX/example.cfg -------------------------------------------------------------------------------- /FIX/README.md: -------------------------------------------------------------------------------- 1 | # FIX README.md 2 | 3 | This is a Python FIX API test suite for Coinbase's Prime FIX APIs. 4 | 5 | # Getting started 6 | 7 | ## 1. Getting into the FIX directory 8 | 9 | If you are currently in the REST directory, you can use the following command: 10 | ``` 11 | cd ~/environment/prime-scripts-py/FIX 12 | ``` 13 | If you did **not** participate in the REST workshop and are only participating in the FIX workshop, you need to clone the repository and then navigate into the FIX repository with these two commands: 14 | ``` 15 | git clone https://github.com/coinbase-samples/prime-scripts-py 16 | cd prime-scripts-py/FIX 17 | ``` 18 | 19 | ## 2. Configuration 20 | 21 | You will need to install two dependencies for this to operate: quickfix and certifi. This allows for Python to successfully connect to Coinbase via FIX. This can be done with the following command: 22 | 23 | ``` 24 | pip install -r requirements.txt 25 | ``` 26 | 27 | We also want to store and grab variables to ensure that you can connect to Prime via FIX. Run the following to declare these variables: 28 | 29 | ```bash 30 | 31 | export ACCESS_KEY=ACCESSKEYHERE 32 | export PASSPHRASE=PASSPHRASEHERE 33 | export SIGNING_KEY=SIGNING_KEYHERE 34 | export PORTFOLIO_ID=PORTFOLIO_IDHERE 35 | export SVC_ACCOUNTID=SVC_ACCOUNTIDHERE 36 | export FIX_VERSION=FIX.4.2 37 | export TARGET_COMP_ID=COIN 38 | ``` 39 | 40 | Connect to FIX with any of the `client_*` scripts, e.g.: 41 | 42 | ``` 43 | python client_create_order.py 44 | ``` -------------------------------------------------------------------------------- /FIX/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coinbase-samples/prime-scripts-py/fe0f5e6b937b0bbc6e25a0f687abd3cfb64249d8/FIX/app/__init__.py -------------------------------------------------------------------------------- /FIX/app/configuration.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import os 15 | import certifi 16 | import configparser 17 | 18 | 19 | class Configuration: 20 | BEGIN_STRING = str(os.environ.get('FIX_VERSION')) 21 | SENDER_COMP_ID = str(os.environ.get('SVC_ACCOUNTID')) 22 | TARGET_COMP_ID = str(os.environ.get('TARGET_COMP_ID')) 23 | CLIENT_CERTIFICATE_KEY_FILE = str(certifi.where()) 24 | 25 | def __init__(self): 26 | self.config = configparser.ConfigParser() 27 | 28 | def build_config(self): 29 | """Function to build example.cfg file for FIX Client""" 30 | self.config['DEFAULT'] = { 31 | 'ConnectionType': 'initiator', 32 | 'StartTime': '00:00:00', 33 | 'EndTime': '00:00:00', 34 | 'UseDataDictionary': 'N', 35 | 'ReconnectInterval': '10', 36 | 'ValidateUserDefinedFields': 'N', 37 | 'ValidateIncomingMessage': 'Y', 38 | 'ResetOnLogon': 'Y', 39 | 'ResetOnLogout': 'N', 40 | 'ResetOnDisconnect': 'Y', 41 | 'ClientCertificateKeyFile': self.CLIENT_CERTIFICATE_KEY_FILE, 42 | 'SSLEnable': 'Y', 43 | 'SSLProtocols': 'Tls12', 44 | 'SocketConnectPort': '4198' 45 | } 46 | 47 | self.config['SESSION'] = { 48 | 'BeginString': self.BEGIN_STRING, 49 | 'SenderCompID': self.SENDER_COMP_ID, 50 | 'TargetCompID': self.TARGET_COMP_ID, 51 | 'HeartBtInt': '30', 52 | 'SocketConnectHost': 'fix.prime.coinbase.com', 53 | 'FileStorePath': './.sessions/' 54 | } 55 | 56 | with open('example.cfg', 'w') as configfile: 57 | self.config.write(configfile) -------------------------------------------------------------------------------- /FIX/app/dictionary.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | last_order_id = '' 16 | last_client_order_id = '' 17 | last_product_id = '' 18 | last_side = '' 19 | last_quantity = '' 20 | 21 | field_msgtype = 35 22 | msgtype_execution_report = '8' 23 | msgtype_reject = '3' 24 | msgtype_logon = 'A' 25 | 26 | field_exectranstype = 20 27 | exectranstype_new = '0' 28 | 29 | field_sendingtime = 52 30 | field_msgseqnum = 34 31 | field_targetcompid = 56 32 | field_text = 58 33 | 34 | field_exectype = 150 35 | exectype_new = '0' 36 | exectype_partial = '1' 37 | exectype_fill = '2' 38 | exectype_cancelled = '4' 39 | exectype_stopped = '7' 40 | exectype_rejected = '8' 41 | exectype_status = 'I' 42 | 43 | field_clordid = 11 44 | field_orderid = 37 45 | field_quantity = 151 46 | field_side = 54 47 | field_productid = 55 48 | 49 | field_password = 554 50 | field_rawdata = 96 51 | field_accesskey = 9407 52 | 53 | side_buy = 'BUY' 54 | side_sell = 'SELL' 55 | 56 | fix_side_buy = '1' 57 | fix_side_sell = '2' 58 | 59 | type_market = 'MARKET' 60 | type_limit = 'LIMIT' 61 | type_twap = 'TWAP' 62 | -------------------------------------------------------------------------------- /FIX/app/fix_session.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import configparser 16 | import quickfix as fix 17 | import logging 18 | import time 19 | import base64 20 | import hmac 21 | import uuid 22 | import json 23 | import hashlib 24 | import os 25 | import sys 26 | from app.logger import setup_logger, format_message 27 | from app.dictionary import * 28 | 29 | setup_logger('logfix') 30 | logfix = logging.getLogger('logfix') 31 | 32 | 33 | class FixSession: 34 | 35 | def __init__(self, session_id, portfolio_id): 36 | self.session_id = session_id 37 | self.portfolio_id = portfolio_id 38 | 39 | def send_message(self, message): 40 | """Sending FIX Messages to API here""" 41 | fix.Session.sendToTarget(message, self.session_id) 42 | 43 | def on_message(self, message): 44 | """Process Application messages here""" 45 | if message.getHeader().getField(field_msgtype) == msgtype_execution_report and '20=0' in str(message): 46 | self.get_exec_type(message) 47 | elif message.getHeader().getField(field_msgtype) == msgtype_reject: 48 | if "58=" in str(message): 49 | reason = message.getField(field_text) 50 | logfix.info('Message Rejected, Reason: {} '.format(reason)) 51 | else: 52 | reason = 'Not Returned' 53 | logfix.info('Message Rejected, Reason: {} '.format(reason)) 54 | 55 | def get_exec_type(self, message): 56 | """Util Function to parse Execution Reports""" 57 | exec_type = message.getField(field_exectype) 58 | if "58=" in str(message): 59 | reason = message.getField(field_text) 60 | else: 61 | reason = 'Not Returned' 62 | order_id = message.getField(field_orderid) 63 | 64 | if exec_type == exectype_new: 65 | logfix.info('New Order - Order Not Filled') 66 | elif exec_type == exectype_partial: 67 | logfix.info('Order - Partial fill') 68 | elif exec_type == exectype_fill: 69 | logfix.info('Order - Filled') 70 | elif exec_type == exectype_cancelled: 71 | logfix.info('Order {} Cancelled, Reason: {}'.format(order_id, reason)) 72 | elif exec_type == exectype_stopped: 73 | logfix.info('Order {} Stopped, Reason: {}'.format(order_id, reason)) 74 | elif exec_type == exectype_rejected: 75 | logfix.info('Order {} Rejected, Reason: {}'.format(order_id, reason)) 76 | elif exec_type == exectype_status: 77 | logfix.info('Order Status for {} : {}'.format(order_id, message)) 78 | else: 79 | return 80 | 81 | 82 | class Application(fix.Application): 83 | 84 | config = configparser.RawConfigParser() 85 | 86 | PASSPHRASE = str(os.environ.get('PASSPHRASE')) 87 | API_KEY = str(os.environ.get('ACCESS_KEY')) 88 | API_SECRET = str(os.environ.get('SIGNING_KEY')) 89 | PORTFOLIO = str(os.environ.get('PORTFOLIO_ID')) 90 | 91 | def __init__(self): 92 | super().__init__() 93 | self.last_order_id = last_order_id 94 | self.last_client_order_id = last_client_order_id 95 | self.last_product_id = last_product_id 96 | self.last_side = last_side 97 | self.last_quantity = last_quantity 98 | self.firstRun = True 99 | 100 | def onCreate(self, sessionID): 101 | """Function called upon FIX Application startup""" 102 | logfix.info('onCreate : Session (%s)' % sessionID.toString()) 103 | self.sessionID = sessionID 104 | self.fixSession = FixSession(self.sessionID, self.PORTFOLIO) 105 | return 106 | 107 | def onLogon(self, sessionID): 108 | """Function called upon Logon""" 109 | logfix.info('---------------Successful Logon----------------') 110 | self.sessionID = sessionID 111 | return 112 | 113 | def onLogout(self, sessionID): 114 | """Function called upon Logout""" 115 | return 116 | 117 | def toAdmin(self, message, sessionID): 118 | """Function called for all outbound Administrative Messages""" 119 | if message.getHeader().getField(field_msgtype) == msgtype_logon: 120 | rawData = self.sign(message.getHeader().getField(field_sendingtime), message.getHeader().getField(field_msgtype), 121 | message.getHeader().getField(field_msgseqnum), self.API_KEY, message.getHeader().getField(field_targetcompid), 122 | self.PASSPHRASE) 123 | message.setField(fix.StringField(field_password, self.PASSPHRASE)) 124 | message.setField(fix.StringField(field_rawdata, rawData)) 125 | message.setField(fix.StringField(field_accesskey, self.API_KEY)) 126 | logfix.info('(Admin) S >> %s' % format_message(message)) 127 | return 128 | else: 129 | return 130 | 131 | def fromAdmin(self, message, sessionID): 132 | """Function called for all inbound Administrative Messages""" 133 | if message.getHeader().getField(field_msgtype) == msgtype_logon: 134 | logfix.info('(Admin) R << %s' % format_message(message)) 135 | self.fixSession.on_message(message) 136 | return 137 | 138 | def toApp(self, message, sessionID): 139 | """Function called for outbound Application Messages""" 140 | logfix.info('(App) S >> %s' % format_message(message)) 141 | self.last_client_order_id = message.getField(field_clordid) 142 | return 143 | 144 | def fromApp(self, message, sessionID): 145 | """Function called for inbound Application Messages""" 146 | logfix.info('(App) R << %s' % format_message(message)) 147 | 148 | try: 149 | if message.getField(field_clordid) == self.last_client_order_id: 150 | self.last_order_id = message.getField(field_orderid) 151 | self.last_quantity = message.getField(field_quantity) 152 | self.last_side = message.getField(field_side) 153 | self.last_product_id = message.getField(field_productid) 154 | 155 | order_details = { 156 | 'last_client_order_id': self.last_client_order_id, 157 | 'last_order_id': self.last_order_id, 158 | 'last_quantity': self.last_quantity, 159 | 'last_side': self.last_side, 160 | 'last_product_id': self.last_product_id 161 | } 162 | 163 | if self.firstRun: 164 | order_json = json.dumps(order_details) 165 | print(order_json) 166 | self.firstRun = False 167 | 168 | except: 169 | print('no message') 170 | self.fixSession.on_message(message) 171 | return 172 | 173 | def sign(self, t, msg_type, seq_num, access_key, target_comp_id, passphrase): 174 | """Function to Generate Authentication Signature""" 175 | message = ''.join([t, msg_type, seq_num, access_key, target_comp_id, passphrase]).encode('utf-8') 176 | hmac_key = self.API_SECRET 177 | signature = hmac.new(hmac_key.encode('utf-8'), message, hashlib.sha256) 178 | sign_b64 = base64.b64encode(signature.digest()).decode() 179 | return sign_b64 180 | 181 | def create_header(self, portfolio_id, message_type): 182 | """Construct FIX header""" 183 | message = fix.Message() 184 | header = message.getHeader() 185 | header.setField(message_type) 186 | message.setField(fix.Account(portfolio_id)) 187 | message.setField(fix.ClOrdID(str(uuid.uuid4()))) 188 | return message 189 | 190 | def build_create_order(self, fixSession, sessionID): 191 | """Construct FIX Message based on User Input""" 192 | time.sleep(3) 193 | self.create_order(fixSession) 194 | time.sleep(6) 195 | self.logout(fixSession, sessionID) 196 | 197 | def build_get_order(self, fixSession, sessionID): 198 | """Construct FIX Message based on User Input""" 199 | time.sleep(3) 200 | self.get_order(fixSession) 201 | time.sleep(6) 202 | self.logout(fixSession, sessionID) 203 | 204 | def build_cancel_order(self, fixSession, sessionID): 205 | """Construct FIX Message based on User Input""" 206 | time.sleep(3) 207 | self.cancel_order(fixSession) 208 | time.sleep(6) 209 | self.logout(fixSession, sessionID) 210 | 211 | def logout(self, fixSession, sessionID): 212 | """Build Cancel Order Message (F) based-on user input""" 213 | logout_message = fix.Message() 214 | header = logout_message.getHeader() 215 | header.setField(fix.MsgType(fix.MsgType_Logout)) 216 | fixSession.send_message(logout_message) 217 | time.sleep(1) 218 | sys.exit() 219 | 220 | def run_create_order(self): 221 | """Run Create Order Application""" 222 | self.build_create_order(self.fixSession, self.sessionID) 223 | 224 | def run_get_order(self): 225 | """Run Get Order Application""" 226 | self.build_get_order(self.fixSession, self.sessionID) 227 | 228 | def run_cancel_order(self): 229 | """Run Cancel Order Application""" 230 | self.build_cancel_order(self.fixSession, self.sessionID) 231 | -------------------------------------------------------------------------------- /FIX/app/logger.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import logging 15 | 16 | loggers = {} 17 | 18 | 19 | def setup_logger(logger_name, level=logging.INFO): 20 | global loggers 21 | 22 | if loggers.get(logger_name): 23 | return loggers.get(logger_name) 24 | 25 | else: 26 | lz = logging.getLogger(logger_name) 27 | lz.setLevel(level) 28 | formatter = logging.Formatter( 29 | '%(asctime)s.%(msecs)03d : %(message)s', 30 | datefmt='%Y-%m-%d,%H:%M:%S') 31 | streamHandler = logging.StreamHandler() 32 | streamHandler.setFormatter(formatter) 33 | lz.addHandler(streamHandler) 34 | 35 | loggers[logger_name] = lz 36 | return lz 37 | 38 | 39 | def format_message(message): 40 | msg = message.toString().replace('\u0001', '|') 41 | return msg 42 | -------------------------------------------------------------------------------- /FIX/build_cancel_order.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License.python c 14 | import os 15 | import quickfix as fix 16 | from app.fix_session import Application 17 | from app.dictionary import * 18 | 19 | 20 | class BuildCancel(Application): 21 | 22 | def cancel_order(self, fixSession): 23 | order_id = os.environ.get('FIX_ORDER_ID') 24 | client_order_id = os.environ.get('FIX_CLIENT_ORDER_ID') 25 | base_quantity = os.environ.get('FIX_QUANTITY') 26 | side = os.environ.get('FIX_SIDE') 27 | product = os.environ.get('FIX_PRODUCT_ID') 28 | 29 | message = self.create_header(fixSession.portfolio_id, fix.MsgType(fix.MsgType_OrderCancelRequest)) 30 | message.setField(fix.OrderID(str(order_id))) 31 | message.setField(fix.OrigClOrdID(str(client_order_id))) 32 | message.setField(fix.Symbol(str(product))) 33 | if side == fix_side_buy: 34 | message.setField(fix.Side(fix.Side_BUY)) 35 | else: 36 | message.setField(fix.Side(fix.Side_SELL)) 37 | message.setField(fix.OrderQty(float(base_quantity))) 38 | fixSession.send_message(message) 39 | -------------------------------------------------------------------------------- /FIX/build_create_order.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import quickfix as fix 15 | from app.fix_session import Application 16 | from app.dictionary import type_market, type_limit, side_buy 17 | 18 | 19 | class BuildCreate(Application): 20 | 21 | def create_order(self, fixSession): 22 | 23 | product = 'ETH-USD' 24 | order_type = 'LIMIT' 25 | side = 'BUY' 26 | base_quantity = '0.0015' 27 | limit_price = '1001' 28 | 29 | message = self.create_header(fixSession.portfolio_id, fix.MsgType(fix.MsgType_NewOrderSingle)) 30 | message.setField(fix.Symbol(product)) 31 | 32 | if order_type == type_market: 33 | message.setField(fix.OrdType(fix.OrdType_MARKET)) 34 | message.setField(fix.TimeInForce('3')) 35 | message.setField(847, 'M') 36 | elif order_type == type_limit: 37 | message.setField(fix.OrdType(fix.OrdType_LIMIT)) 38 | message.setField(fix.TimeInForce('1')) 39 | message.setField(847, 'L') 40 | message.setField(fix.Price(float(limit_price))) 41 | if side == side_buy: 42 | message.setField(fix.Side(fix.Side_BUY)) 43 | else: 44 | message.setField(fix.Side(fix.Side_SELL)) 45 | message.setField(fix.OrderQty(float(base_quantity))) 46 | 47 | fixSession.send_message(message) 48 | -------------------------------------------------------------------------------- /FIX/build_get_order.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import os 15 | import quickfix as fix 16 | from app.fix_session import Application 17 | 18 | 19 | class BuildGet(Application): 20 | 21 | def get_order(self,fixSession): 22 | """Build Order Status Message (H) based-on user input""" 23 | order_id = os.environ.get('FIX_ORDER_ID') 24 | 25 | message = self.create_header(fixSession.portfolio_id, fix.MsgType(fix.MsgType_OrderStatusRequest)) 26 | message.setField(fix.OrderID(order_id)) 27 | 28 | fixSession.send_message(message) 29 | 30 | -------------------------------------------------------------------------------- /FIX/client_cancel_order.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import quickfix 15 | from app.configuration import Configuration 16 | from build_cancel_order import BuildCancel 17 | 18 | 19 | def main(): 20 | try: 21 | Configuration().build_config() 22 | settings = quickfix.SessionSettings('example.cfg', True) 23 | 24 | build = BuildCancel() 25 | 26 | storefactory = quickfix.FileStoreFactory(settings) 27 | initiator = quickfix.SSLSocketInitiator(build, storefactory, settings) 28 | 29 | initiator.start() 30 | build.run_cancel_order() 31 | 32 | except (quickfix.ConfigError, quickfix.RuntimeError) as exception: 33 | assert type(exception).__name__ == 'NameError' 34 | 35 | 36 | if __name__ == '__main__': 37 | main() 38 | -------------------------------------------------------------------------------- /FIX/client_create_order.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import quickfix 15 | from app.configuration import Configuration 16 | import configparser 17 | from build_create_order import BuildCreate 18 | 19 | config = configparser.ConfigParser() 20 | 21 | 22 | def main(): 23 | """Main""" 24 | try: 25 | Configuration().build_config() 26 | settings = quickfix.SessionSettings('example.cfg', True) 27 | 28 | build = BuildCreate() 29 | 30 | storefactory = quickfix.FileStoreFactory(settings) 31 | initiator = quickfix.SSLSocketInitiator(build, storefactory, settings) 32 | 33 | initiator.start() 34 | build.run_create_order() 35 | 36 | except (quickfix.ConfigError, quickfix.RuntimeError) as exception: 37 | assert type(exception).__name__ == 'NameError' 38 | 39 | 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /FIX/client_get_order.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import quickfix 15 | from app.configuration import Configuration 16 | from build_get_order import BuildGet 17 | 18 | 19 | def main(): 20 | """Main""" 21 | try: 22 | Configuration().build_config() 23 | settings = quickfix.SessionSettings('example.cfg', True) 24 | 25 | build = BuildGet() 26 | 27 | storefactory = quickfix.FileStoreFactory(settings) 28 | initiator = quickfix.SSLSocketInitiator(build, storefactory, settings) 29 | 30 | initiator.start() 31 | build.run_get_order() 32 | 33 | except (quickfix.ConfigError, quickfix.RuntimeError) as exception: 34 | assert type(exception).__name__ == 'NameError' 35 | 36 | 37 | if __name__ == '__main__': 38 | main() 39 | -------------------------------------------------------------------------------- /FIX/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2024.7.4 2 | quickfix-ssl==1.15.1.post4 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2023 Coinbase Global, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Purpose 2 | 3 | This repository demonstrates REST, WebSocket, and FIX APIs supported by Coinbase Prime. 4 | 5 | Prime workshop link here: [https://prime.saworkshop.dev/](https://prime.saworkshop.dev/) 6 | 7 | ## Installation 8 | 9 | Simply clone the repo to run scripts from your command line. Then, review the relevant README.md within each subdirectory for more details. 10 | 11 | ```bash 12 | git clone https://github.com/coinbase-samples/prime-scripts-py 13 | ``` -------------------------------------------------------------------------------- /REST/README.md: -------------------------------------------------------------------------------- 1 | # Purpose 2 | 3 | This repository of Python scripts demonstrates various REST and WebSocket APIs supported by Coinbase Prime. 4 | 5 | While originally designed to power the Coinbase Prime Workshop, these scripts will work on their own with proper API credentials. 6 | 7 | Prime workshop link here: [https://prime.saworkshop.dev/](https://prime.saworkshop.dev/) 8 | 9 | All scripts are written in Python3 and have been tested with versions that are not end of life. 10 | 11 | ## Installation 12 | 13 | Simply clone the repo to run scripts from your command line. 14 | 15 | ```bash 16 | git clone https://github.com/coinbase-samples/prime-scripts-py 17 | ``` 18 | 19 | The two dependencies needed for these scripts are `requests` and `websockets`. This can be done easily with the following command: 20 | 21 | ``` 22 | pip install -r requirements.txt 23 | ``` 24 | 25 | Finally, these scripts make use of command line environment variables so that sensitive information does not need to be included in the scripts themselves. Update the following information and run from your command line or choose your favorite method of storing sensitive information to proceed. 26 | 27 | ``` 28 | export ACCESS_KEY=ACCESS_KEY_HERE 29 | export PASSPHRASE=PASSPHRASE_HERE 30 | export SIGNING_KEY=SIGNING_KEY_HERE 31 | export PORTFOLIO_ID=PORTFOLIO_ID_HERE 32 | export SVC_ACCOUNTID=SVC_ACCOUNTID_HERE 33 | ``` 34 | 35 | ## Contributing 36 | Pull requests are welcome. For major changes, please open an issue to discuss what you would like to change. 37 | -------------------------------------------------------------------------------- /REST/prime_cancel_order.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, uuid, os, base64, requests, sys 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | try: 24 | order_id = sys.argv[1] 25 | except IndexError: 26 | sys.exit('Please provide order_id as a command line argument.') 27 | 28 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/orders/{order_id}/cancel' 29 | url_path = urlparse(uri).path 30 | timestamp = str(int(time.time())) 31 | client_order_id = uuid.uuid4() 32 | 33 | payload = { 34 | 'portfolio_id': PORTFOLIO_ID, 35 | 'order_id': order_id 36 | } 37 | 38 | message = timestamp + 'POST' + url_path + json.dumps(payload) 39 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 40 | 41 | headers = { 42 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 43 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 44 | 'X-CB-ACCESS-KEY': API_KEY, 45 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 46 | 'Accept': 'application/json' 47 | } 48 | 49 | response = requests.post(uri, json=payload, headers=headers) 50 | parsed_response = json.loads(response.text) 51 | print(json.dumps(parsed_response, indent=3)) 52 | -------------------------------------------------------------------------------- /REST/prime_create_address_book_entry.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, uuid, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | ADDRESS = os.environ.get('BLOCKCHAIN_ADDRESS') 23 | NAME = os.environ.get('ADDRESS_NAME') 24 | 25 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/address_book' 26 | timestamp = str(int(time.time())) 27 | client_order_id = uuid.uuid4() 28 | symbol = 'ETH' 29 | 30 | payload = { 31 | 'portfolio_id': PORTFOLIO_ID, 32 | 'address': ADDRESS, 33 | 'currency_symbol': symbol, 34 | 'name': NAME 35 | } 36 | 37 | url_path = urlparse(uri).path 38 | message = timestamp + 'POST' + url_path + json.dumps(payload) 39 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 40 | 41 | headers = { 42 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 43 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 44 | 'X-CB-ACCESS-KEY': API_KEY, 45 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 46 | 'Accept': 'application/json' 47 | } 48 | 49 | response = requests.post(uri, json=payload, headers=headers) 50 | parsed_response = json.loads(response.text) 51 | print(json.dumps(parsed_response,indent=3)) 52 | -------------------------------------------------------------------------------- /REST/prime_create_allocations.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import json, hmac, hashlib, time, uuid, os, base64, requests, argparse, sys 15 | from urllib.parse import urlparse 16 | 17 | # Must be entity or organization API key 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | ORIGIN_PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = 'https://api.prime.coinbase.com/v1/allocations' 24 | timestamp = str(int(time.time())) 25 | allocation_id = uuid.uuid4() 26 | allocation_leg_id = uuid.uuid4() 27 | 28 | product_id = 'ETH-USD' 29 | size_type = 'PERCENT' 30 | 31 | parser = argparse.ArgumentParser(description='Allocate funds to multiple portfolios') 32 | parser.add_argument('--destination_portfolio_ids', '-d', nargs='+', required=True, 33 | help='The UUIDs of the destination portfolios to which funds will be allocated') 34 | parser.add_argument('--order_ids', '-o', nargs='+', required=True, 35 | help='The UUIDs of the orders to be allocated to the destination portfolios') 36 | 37 | args = parser.parse_args() 38 | 39 | if not args.destination_portfolio_ids or not args.order_ids: 40 | sys.exit('Error: at least one value for both --destination_portfolio_ids and --order_ids is required') 41 | 42 | # Calculate amount per destination_portfolio_id. Defaults to equal distribution 43 | amount = 100 / len(args.destination_portfolio_ids) 44 | 45 | allocation_legs = [] 46 | for dest_portfolio_id in args.destination_portfolio_ids: 47 | allocation_legs.append({ 48 | 'allocation_leg_id': allocation_leg_id, 49 | 'destination_portfolio_id': dest_portfolio_id, 50 | 'amount': str(amount) 51 | }) 52 | 53 | payload = { 54 | 'allocation_id': str(allocation_id), 55 | 'source_portfolio_id': ORIGIN_PORTFOLIO_ID, 56 | 'product_id': product_id, 57 | 'order_ids': args.order_ids, 58 | 'allocation_legs': allocation_legs, 59 | 'size_type': size_type 60 | } 61 | 62 | url_path = urlparse(uri).path 63 | message = timestamp + 'POST' + url_path + json.dumps(payload) 64 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 65 | 66 | headers = { 67 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 68 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 69 | 'X-CB-ACCESS-KEY': API_KEY, 70 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 71 | 'Accept': 'application/json' 72 | } 73 | response = requests.post(uri, json=payload, headers=headers) 74 | parsed_response = json.loads(response.text) 75 | print(json.dumps(parsed_response, indent=3)) 76 | -------------------------------------------------------------------------------- /REST/prime_create_conversion.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, uuid, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | wallet_id = 'WALLET_UUID' 24 | 25 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/wallets/{wallet_id}/conversion' 26 | 27 | timestamp = str(int(time.time())) 28 | 29 | # only supports conversions between USDC and USD 30 | amount = '1' 31 | destination = 'DESTINATION_WALLET_UUID' 32 | idempotency_key = uuid.uuid4() 33 | source_symbol = 'USD' 34 | destination_symbol = 'USDC' 35 | 36 | payload = { 37 | 'portfolio_id': PORTFOLIO_ID, 38 | 'wallet_id': wallet_id, 39 | 'amount': amount, 40 | 'destination': destination, 41 | 'idempotency_key': str(idempotency_key), 42 | 'source_symbol': source_symbol, 43 | 'destination_symbol': destination_symbol 44 | } 45 | 46 | url_path = urlparse(uri).path 47 | message = timestamp + 'POST' + url_path + json.dumps(payload) 48 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 49 | 50 | headers = { 51 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 52 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 53 | 'X-CB-ACCESS-KEY': API_KEY, 54 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 55 | 'Accept': 'application/json' 56 | } 57 | 58 | response = requests.post(uri, json=payload, headers=headers) 59 | parsed_response = json.loads(response.text) 60 | print(json.dumps(parsed_response, indent=3)) -------------------------------------------------------------------------------- /REST/prime_create_order.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, uuid, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/order' 24 | 25 | timestamp = str(int(time.time())) 26 | client_order_id = uuid.uuid4() 27 | 28 | product_id = 'ETH-USD' 29 | side = 'BUY' 30 | order_type = 'MARKET' 31 | base_quantity = '0.001' 32 | 33 | payload = { 34 | 'portfolio_id': PORTFOLIO_ID, 35 | 'product_id': product_id, 36 | 'client_order_id': str(client_order_id), 37 | 'side': side, 38 | 'type': order_type, 39 | 'base_quantity': base_quantity 40 | } 41 | 42 | url_path = urlparse(uri).path 43 | message = timestamp + 'POST' + url_path + json.dumps(payload) 44 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 45 | 46 | headers = { 47 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 48 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 49 | 'X-CB-ACCESS-KEY': API_KEY, 50 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 51 | 'Accept': 'application/json' 52 | } 53 | 54 | response = requests.post(uri, json=payload, headers=headers) 55 | parsed_response = json.loads(response.text) 56 | 57 | order_id = parsed_response['order_id'] 58 | print(order_id) 59 | -------------------------------------------------------------------------------- /REST/prime_create_order_preview.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, uuid, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/order_preview' 24 | timestamp = str(int(time.time())) 25 | client_order_id = uuid.uuid4() 26 | 27 | product_id = 'ETH-USD' 28 | side = 'BUY' 29 | order_type = 'MARKET' 30 | base_quantity = '0.001' 31 | 32 | payload = { 33 | 'portfolio_id': PORTFOLIO_ID, 34 | 'product_id': product_id, 35 | 'client_order_id': str(client_order_id), 36 | 'side': side, 37 | 'type': order_type, 38 | 'base_quantity': base_quantity 39 | } 40 | 41 | url_path = urlparse(uri).path 42 | message = timestamp + 'POST' + url_path + json.dumps(payload) 43 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 44 | 45 | headers = { 46 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 47 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 48 | 'X-CB-ACCESS-KEY': API_KEY, 49 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 50 | 'Accept': 'application/json' 51 | } 52 | 53 | response = requests.post(uri, json=payload, headers=headers) 54 | parsed_response = json.loads(response.text) 55 | print(json.dumps(parsed_response, indent=3)) 56 | -------------------------------------------------------------------------------- /REST/prime_create_rfq_always_accept.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import sys 17 | import json 18 | import time 19 | import uuid 20 | import hmac 21 | import hashlib 22 | import base64 23 | import requests 24 | import argparse 25 | from urllib.parse import urlparse 26 | 27 | # ------------------------------------------------------------------------------ 28 | # Argument Parsing 29 | # Example usage: 30 | # python prime_create_rfq_always_accept.py --product SOL-USD --side BUY --size 0.5 --limit 350 31 | # ------------------------------------------------------------------------------ 32 | parser = argparse.ArgumentParser( 33 | description="Create and accept an RFQ using Coinbase Prime." 34 | ) 35 | parser.add_argument("--product", required=True, help="Product pair, e.g. SOL-USD") 36 | parser.add_argument("--side", required=True, choices=["BUY", "SELL"], help="Trade side (BUY or SELL)") 37 | parser.add_argument("--size", required=True, help="Base quantity to trade, e.g. 0.5") 38 | parser.add_argument("--limit", required=True, help="Limit price, e.g. 350") 39 | args = parser.parse_args() 40 | 41 | API_KEY = os.environ.get('ACCESS_KEY') 42 | SECRET_KEY = os.environ.get('SIGNING_KEY') 43 | PASSPHRASE = os.environ.get('PASSPHRASE') 44 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 45 | 46 | product_id = args.product 47 | side = args.side.upper() 48 | limit_price = args.limit 49 | base_quantity = args.size 50 | order_type = 'RFQ' 51 | 52 | def sign_headers(method: str, url: str, payload: dict) -> dict: 53 | timestamp = str(int(time.time())) 54 | url_path = urlparse(url).path 55 | message = timestamp + method.upper() + url_path + json.dumps(payload) 56 | signature = base64.b64encode( 57 | hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256) 58 | ) 59 | return { 60 | 'X-CB-ACCESS-SIGNATURE': signature, 61 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 62 | 'X-CB-ACCESS-KEY': API_KEY, 63 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 64 | 'Accept': 'application/json', 65 | 'Content-Type': 'application/json' 66 | } 67 | 68 | # ------------------------------------------------------------------------------ 69 | # 1) Create an RFQ 70 | # ------------------------------------------------------------------------------ 71 | rfq_url = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/rfq' 72 | client_quote_id = str(uuid.uuid4()) 73 | 74 | rfq_payload = { 75 | 'portfolio_id': PORTFOLIO_ID, 76 | 'product_id': product_id, 77 | 'client_quote_id': client_quote_id, 78 | 'side': side, 79 | 'limit_price': limit_price, 80 | 'type': order_type, 81 | 'base_quantity': base_quantity 82 | } 83 | 84 | headers = sign_headers('POST', rfq_url, rfq_payload) 85 | rfq_response = requests.post(rfq_url, json=rfq_payload, headers=headers) 86 | rfq_parsed = rfq_response.json() 87 | 88 | print("=== RFQ Response ===") 89 | print(json.dumps(rfq_parsed, indent=3)) 90 | 91 | quote_id = rfq_parsed.get("quote_id") 92 | if not quote_id: 93 | print("Failed to get a quote_id from the RFQ response.") 94 | sys.exit(1) 95 | 96 | # ------------------------------------------------------------------------------ 97 | # 2) Accept the Quote 98 | # ------------------------------------------------------------------------------ 99 | time.sleep(0.5) # small pause 100 | 101 | accept_url = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/accept_quote' 102 | accept_payload = { 103 | 'portfolio_id': PORTFOLIO_ID, 104 | 'product_id': product_id, 105 | 'side': side, 106 | 'client_order_id': client_quote_id, 107 | 'quote_id': quote_id 108 | } 109 | 110 | headers = sign_headers('POST', accept_url, accept_payload) 111 | accept_response = requests.post(accept_url, json=accept_payload, headers=headers) 112 | accept_parsed = accept_response.json() 113 | 114 | print("\n=== Accept Quote Response ===") 115 | print(json.dumps(accept_parsed, indent=3)) 116 | print("HTTP Status:", accept_response.status_code, accept_response.text) 117 | -------------------------------------------------------------------------------- /REST/prime_create_rfq_compare_clob.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import sys 17 | import json 18 | import time 19 | import uuid 20 | import hmac 21 | import base64 22 | import hashlib 23 | import requests 24 | import argparse 25 | from urllib.parse import urlparse 26 | 27 | # ------------------------------------------------------------------------------ 28 | # Command-line arguments 29 | # Usage example: 30 | # python prime_create_rfq_compare_clob.py --product ETH-USD --side BUY --size 0.004 --limit 3000 31 | # ------------------------------------------------------------------------------ 32 | parser = argparse.ArgumentParser( 33 | description="Create and accept an RFQ or place an order based on comparison with the CLOB." 34 | ) 35 | parser.add_argument("--product", required=True, help="Product pair, e.g. ETH-USD") 36 | parser.add_argument("--side", required=True, choices=["BUY", "SELL"], help="Trade side (BUY or SELL)") 37 | parser.add_argument("--size", required=True, help="Base quantity to trade, e.g. 0.004") 38 | parser.add_argument("--limit", required=True, help="Limit price, e.g. 3000") 39 | args = parser.parse_args() 40 | 41 | product_id = args.product 42 | side = args.side 43 | base_quantity = args.size 44 | limit_price = args.limit 45 | 46 | # ------------------------------------------------------------------------------ 47 | # Environment variables for authentication 48 | # ------------------------------------------------------------------------------ 49 | API_KEY = os.environ.get("ACCESS_KEY") 50 | SECRET_KEY = os.environ.get("SIGNING_KEY") 51 | PASSPHRASE = os.environ.get("PASSPHRASE") 52 | PORTFOLIO_ID = os.environ.get("PORTFOLIO_ID") 53 | 54 | def sign_payload(timestamp, method, path, body): 55 | message = timestamp + method + path + json.dumps(body) 56 | signature = hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256) 57 | return base64.b64encode(signature) 58 | 59 | # ------------------------------------------------------------------------------ 60 | # 1) Create an Order Preview (CLOB) 61 | # ------------------------------------------------------------------------------ 62 | client_order_id = str(uuid.uuid4()) 63 | preview_uri = f"https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/order_preview" 64 | preview_timestamp = str(int(time.time())) 65 | 66 | preview_payload = { 67 | "portfolio_id": PORTFOLIO_ID, 68 | "product_id": product_id, 69 | "side": side, 70 | "type": "LIMIT", 71 | "limit_price": limit_price, 72 | "base_quantity": base_quantity, 73 | } 74 | 75 | preview_path = urlparse(preview_uri).path 76 | preview_signature_b64 = sign_payload(preview_timestamp, "POST", preview_path, preview_payload) 77 | 78 | preview_headers = { 79 | "X-CB-ACCESS-SIGNATURE": preview_signature_b64, 80 | "X-CB-ACCESS-TIMESTAMP": preview_timestamp, 81 | "X-CB-ACCESS-KEY": API_KEY, 82 | "X-CB-ACCESS-PASSPHRASE": PASSPHRASE, 83 | "Accept": "application/json", 84 | "Content-Type": "application/json", 85 | } 86 | 87 | print("=== Creating Order Preview (CLOB) ===") 88 | preview_res = requests.post(preview_uri, json=preview_payload, headers=preview_headers) 89 | preview_parsed = preview_res.json() 90 | print(json.dumps(preview_parsed, indent=3)) 91 | 92 | clob_avg_fill_price = float(preview_parsed.get("average_filled_price", 0.0)) 93 | 94 | # ------------------------------------------------------------------------------ 95 | # 2) Create an RFQ 96 | # ------------------------------------------------------------------------------ 97 | rfq_uri = f"https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/rfq" 98 | rfq_timestamp = str(int(time.time())) 99 | rfq_client_quote_id = str(uuid.uuid4()) 100 | 101 | rfq_payload = { 102 | "portfolio_id": PORTFOLIO_ID, 103 | "product_id": product_id, 104 | "client_quote_id": rfq_client_quote_id, 105 | "side": side, 106 | "limit_price": limit_price, 107 | "type": "RFQ", 108 | "base_quantity": base_quantity, 109 | } 110 | 111 | rfq_path = urlparse(rfq_uri).path 112 | rfq_signature_b64 = sign_payload(rfq_timestamp, "POST", rfq_path, rfq_payload) 113 | 114 | rfq_headers = { 115 | "X-CB-ACCESS-SIGNATURE": rfq_signature_b64, 116 | "X-CB-ACCESS-TIMESTAMP": rfq_timestamp, 117 | "X-CB-ACCESS-KEY": API_KEY, 118 | "X-CB-ACCESS-PASSPHRASE": PASSPHRASE, 119 | "Accept": "application/json", 120 | "Content-Type": "application/json", 121 | } 122 | 123 | print("\n=== Creating RFQ ===") 124 | rfq_res = requests.post(rfq_uri, json=rfq_payload, headers=rfq_headers) 125 | rfq_parsed = rfq_res.json() 126 | print(json.dumps(rfq_parsed, indent=3)) 127 | 128 | quote_id = rfq_parsed.get("quote_id", "") 129 | rfq_best_price = float(rfq_parsed.get("best_price", 0.0)) 130 | 131 | # ------------------------------------------------------------------------------ 132 | # 3) Compare prices (For BUY: lower is better; for SELL: higher is better) 133 | # ------------------------------------------------------------------------------ 134 | print("\n=== Comparison ===") 135 | print(f"RFQ best_price: {rfq_best_price}") 136 | print(f"CLOB average_filled_price: {clob_avg_fill_price}") 137 | 138 | def is_rfq_better(side_str, rfq_price, clob_price): 139 | if side_str.upper() == "BUY": 140 | return rfq_price < clob_price 141 | elif side_str.upper() == "SELL": 142 | return rfq_price > clob_price 143 | else: 144 | raise ValueError("Side must be 'BUY' or 'SELL'") 145 | 146 | rfq_is_better = is_rfq_better(side, rfq_best_price, clob_avg_fill_price) 147 | 148 | # ------------------------------------------------------------------------------ 149 | # 4) If RFQ is better -> Accept the quote; else -> Place a real order 150 | # ------------------------------------------------------------------------------ 151 | if rfq_is_better: 152 | print("RFQ is better than CLOB price. Accepting the quote...") 153 | 154 | accept_uri = f"https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/accept_quote" 155 | accept_timestamp = str(int(time.time())) 156 | accept_payload = { 157 | "portfolio_id": PORTFOLIO_ID, 158 | "product_id": product_id, 159 | "side": side, 160 | "client_order_id": client_order_id, # or generate new 161 | "quote_id": quote_id, 162 | } 163 | 164 | accept_path = urlparse(accept_uri).path 165 | accept_signature_b64 = sign_payload(accept_timestamp, "POST", accept_path, accept_payload) 166 | 167 | accept_headers = { 168 | "X-CB-ACCESS-SIGNATURE": accept_signature_b64, 169 | "X-CB-ACCESS-TIMESTAMP": accept_timestamp, 170 | "X-CB-ACCESS-KEY": API_KEY, 171 | "X-CB-ACCESS-PASSPHRASE": PASSPHRASE, 172 | "Accept": "application/json", 173 | "Content-Type": "application/json", 174 | } 175 | 176 | accept_res = requests.post(accept_uri, json=accept_payload, headers=accept_headers) 177 | accept_parsed = accept_res.json() 178 | 179 | print("\n=== Accept Quote Response ===") 180 | print(json.dumps(accept_parsed, indent=3)) 181 | print(f"HTTP Status: {accept_res.status_code}") 182 | else: 183 | print("CLOB is better or equal. Placing a real LIMIT order on the CLOB...") 184 | 185 | order_uri = f"https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/order" 186 | order_timestamp = str(int(time.time())) 187 | actual_client_order_id = str(uuid.uuid4()) 188 | 189 | order_payload = { 190 | "portfolio_id": PORTFOLIO_ID, 191 | "product_id": product_id, 192 | "side": side, 193 | "type": "LIMIT", 194 | "limit_price": limit_price, 195 | "base_quantity": base_quantity, 196 | "client_order_id": actual_client_order_id 197 | } 198 | 199 | order_path = urlparse(order_uri).path 200 | order_signature_b64 = sign_payload(order_timestamp, "POST", order_path, order_payload) 201 | 202 | order_headers = { 203 | "X-CB-ACCESS-SIGNATURE": order_signature_b64, 204 | "X-CB-ACCESS-TIMESTAMP": order_timestamp, 205 | "X-CB-ACCESS-KEY": API_KEY, 206 | "X-CB-ACCESS-PASSPHRASE": PASSPHRASE, 207 | "Accept": "application/json", 208 | "Content-Type": "application/json", 209 | } 210 | 211 | order_res = requests.post(order_uri, json=order_payload, headers=order_headers) 212 | order_parsed = order_res.json() 213 | 214 | print("\n=== Place Order Response ===") 215 | print(json.dumps(order_parsed, indent=3)) 216 | print(f"HTTP Status: {order_res.status_code}") 217 | -------------------------------------------------------------------------------- /REST/prime_create_transfer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, uuid, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | ORIGIN_WALLET_ID = os.environ.get('ORIGIN_WALLET_ID') 23 | DESTINATION_WALLET_ID = os.environ.get('WALLET_ID') 24 | 25 | currency_symbol = 'ETH' 26 | amount = '0.001' 27 | 28 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/wallets/{ORIGIN_WALLET_ID}/transfers' 29 | timestamp = str(int(time.time())) 30 | idempotency_key = str(uuid.uuid4()) 31 | 32 | payload = { 33 | 'portfolio_id': PORTFOLIO_ID, 34 | 'wallet_id': ORIGIN_WALLET_ID, 35 | 'amount': amount, 36 | 'destination': DESTINATION_WALLET_ID, 37 | 'idempotency_key': idempotency_key, 38 | 'currency_symbol': currency_symbol 39 | } 40 | 41 | url_path = urlparse(uri).path 42 | message = timestamp + 'POST' + url_path + json.dumps(payload) 43 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 44 | 45 | headers = { 46 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 47 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 48 | 'X-CB-ACCESS-KEY': API_KEY, 49 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 50 | 'Accept': 'application/json' 51 | } 52 | 53 | response = requests.post(uri, json=payload, headers=headers) 54 | parsed_response = json.loads(response.text) 55 | print(json.dumps(parsed_response, indent=3)) 56 | -------------------------------------------------------------------------------- /REST/prime_create_wallet.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, uuid, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | WALLET_NAME = os.environ.get('WALLET_NAME') 23 | 24 | symbol = 'eth' 25 | wallet_type = 'VAULT' 26 | 27 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/wallets' 28 | timestamp = str(int(time.time())) 29 | idempotency_key = uuid.uuid4() 30 | 31 | payload = { 32 | 'portfolio_id': PORTFOLIO_ID, 33 | 'name': WALLET_NAME, 34 | 'symbol': symbol, 35 | 'wallet_type': wallet_type 36 | } 37 | 38 | url_path = urlparse(uri).path 39 | message = timestamp + 'POST' + url_path + json.dumps(payload) 40 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 41 | 42 | headers = { 43 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 44 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 45 | 'X-CB-ACCESS-KEY': API_KEY, 46 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 47 | 'Accept': 'application/json' 48 | } 49 | response = requests.post(uri, json=payload, headers=headers) 50 | parsed_response = json.loads(response.text) 51 | print(json.dumps(parsed_response, indent=3)) 52 | -------------------------------------------------------------------------------- /REST/prime_create_withdrawal.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, uuid, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | ORIGIN_WALLET_ID = os.environ.get('WALLET_ID') 23 | DESTINATION_WALLET_ADDRESS = os.environ.get('BLOCKCHAIN_ADDRESS') 24 | 25 | amount = '0.001' 26 | currency_symbol = 'eth' 27 | destination_type = 'DESTINATION_BLOCKCHAIN' 28 | 29 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/wallets/{ORIGIN_WALLET_ID}/withdrawals' 30 | timestamp = str(int(time.time())) 31 | idempotency_key = str(uuid.uuid4()) 32 | 33 | payload = { 34 | 'portfolio_id': PORTFOLIO_ID, 35 | 'wallet_id': ORIGIN_WALLET_ID, 36 | 'amount': amount, 37 | 'destination_type': destination_type, 38 | 'idempotency_key': idempotency_key, 39 | 'currency_symbol': currency_symbol, 40 | 'blockchain_address': { 41 | 'address': DESTINATION_WALLET_ADDRESS 42 | } 43 | } 44 | 45 | url_path = urlparse(uri).path 46 | message = timestamp + 'POST' + url_path + json.dumps(payload) 47 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 48 | 49 | headers = { 50 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 51 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 52 | 'X-CB-ACCESS-KEY': API_KEY, 53 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 54 | 'Accept': 'application/json' 55 | } 56 | response = requests.post(uri, json=payload, headers=headers) 57 | parsed_response = json.loads(response.text) 58 | print(json.dumps(parsed_response, indent=3)) 59 | -------------------------------------------------------------------------------- /REST/prime_create_withdrawal_to_payment_method.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, uuid, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | USD_TRADING_BALANCE_ID = os.environ.get('USD_TRADING_BALANCE_ID') 23 | PAYMENT_METHOD_ID = os.environ.get('PAYMENT_METHOD_ID') 24 | 25 | amount = '1' 26 | currency_symbol = 'USD' 27 | destination_type = 'DESTINATION_PAYMENT_METHOD' 28 | 29 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/wallets/{USD_TRADING_BALANCE_ID}/withdrawals' 30 | timestamp = str(int(time.time())) 31 | idempotency_key = str(uuid.uuid4()) 32 | 33 | payload = { 34 | 'portfolio_id': PORTFOLIO_ID, 35 | 'wallet_id': USD_TRADING_BALANCE_ID, 36 | 'amount': amount, 37 | 'destination_type': destination_type, 38 | 'idempotency_key': idempotency_key, 39 | 'currency_symbol': currency_symbol, 40 | 'payment_method': { 41 | 'payment_method_id': PAYMENT_METHOD_ID 42 | } 43 | } 44 | 45 | url_path = urlparse(uri).path 46 | message = timestamp + 'POST' + url_path + json.dumps(payload) 47 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 48 | 49 | headers = { 50 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 51 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 52 | 'X-CB-ACCESS-KEY': API_KEY, 53 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 54 | 'Accept': 'application/json' 55 | } 56 | response = requests.post(uri, json=payload, headers=headers) 57 | parsed_response = json.loads(response.text) 58 | print(json.dumps(parsed_response, indent=3)) 59 | -------------------------------------------------------------------------------- /REST/prime_get_activity_by_id.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import sys, json, hmac, hashlib, time, os, base64, requests 15 | from urllib.parse import urlparse 16 | 17 | API_KEY = os.environ.get('ACCESS_KEY') 18 | SECRET_KEY = os.environ.get('SIGNING_KEY') 19 | PASSPHRASE = os.environ.get('PASSPHRASE') 20 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 21 | 22 | try: 23 | activity_id = sys.argv[1] 24 | except IndexError: 25 | sys.exit('Please provide activity_id as a command line argument.') 26 | 27 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/activities/{activity_id}' 28 | url_path = urlparse(uri).path 29 | timestamp = str(int(time.time())) 30 | message = timestamp + 'GET' + url_path 31 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 32 | 33 | headers = { 34 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 35 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 36 | 'X-CB-ACCESS-KEY': API_KEY, 37 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 38 | 'Accept': 'application/json' 39 | } 40 | 41 | response = requests.get(uri, headers=headers) 42 | parsed_response = json.loads(response.text) 43 | print(json.dumps(parsed_response, indent=3)) 44 | -------------------------------------------------------------------------------- /REST/prime_get_allocation_by_id.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import sys, json, hmac, hashlib, time, os, base64, requests 15 | from urllib.parse import urlparse 16 | 17 | API_KEY = os.environ.get('ACCESS_KEY') 18 | SECRET_KEY = os.environ.get('SIGNING_KEY') 19 | PASSPHRASE = os.environ.get('PASSPHRASE') 20 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 21 | 22 | try: 23 | allocation_id = sys.argv[1] 24 | except IndexError: 25 | sys.exit("Please provide allocation_id as a command line argument.") 26 | 27 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/allocations/{allocation_id}' 28 | url_path = urlparse(uri).path 29 | timestamp = str(int(time.time())) 30 | message = timestamp + 'GET' + url_path 31 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 32 | 33 | headers = { 34 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 35 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 36 | 'X-CB-ACCESS-KEY': API_KEY, 37 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 38 | 'Accept': 'application/json' 39 | } 40 | 41 | response = requests.get(uri, headers=headers) 42 | parsed_response = json.loads(response.text) 43 | print(json.dumps(parsed_response, indent=3)) 44 | -------------------------------------------------------------------------------- /REST/prime_get_commission.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/commission' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_get_entity_activity_by_id.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import sys, json, hmac, hashlib, time, os, base64, requests 15 | from urllib.parse import urlparse 16 | 17 | API_KEY = os.environ.get('ACCESS_KEY') 18 | SECRET_KEY = os.environ.get('SIGNING_KEY') 19 | PASSPHRASE = os.environ.get('PASSPHRASE') 20 | 21 | try: 22 | activity_id = sys.argv[1] 23 | except IndexError: 24 | sys.exit('Please provide activity_id as a command line argument.') 25 | 26 | uri = f'https://api.prime.coinbase.com/v1/activities/{activity_id}' 27 | url_path = urlparse(uri).path 28 | timestamp = str(int(time.time())) 29 | message = timestamp + 'GET' + url_path 30 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 31 | 32 | headers = { 33 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 34 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 35 | 'X-CB-ACCESS-KEY': API_KEY, 36 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 37 | 'Accept': 'application/json' 38 | } 39 | 40 | response = requests.get(uri, headers=headers) 41 | parsed_response = json.loads(response.text) 42 | print(json.dumps(parsed_response, indent=3)) 43 | -------------------------------------------------------------------------------- /REST/prime_get_net_allocation_by_id.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import sys, json, hmac, hashlib, time, os, base64, requests 15 | from urllib.parse import urlparse 16 | 17 | API_KEY = os.environ.get('ACCESS_KEY') 18 | SECRET_KEY = os.environ.get('SIGNING_KEY') 19 | PASSPHRASE = os.environ.get('PASSPHRASE') 20 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 21 | 22 | try: 23 | netting_id = sys.argv[1] 24 | except IndexError: 25 | sys.exit("Please provide netting_id as a command line argument.") 26 | 27 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/allocations/net/{netting_id}' 28 | url_path = urlparse(uri).path 29 | timestamp = str(int(time.time())) 30 | message = timestamp + 'GET' + url_path 31 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 32 | 33 | headers = { 34 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 35 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 36 | 'X-CB-ACCESS-KEY': API_KEY, 37 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 38 | 'Accept': 'application/json' 39 | } 40 | 41 | response = requests.get(uri, headers=headers) 42 | parsed_response = json.loads(response.text) 43 | print(json.dumps(parsed_response, indent=3)) 44 | -------------------------------------------------------------------------------- /REST/prime_get_order_by_id.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | ORDER_ID = os.environ.get('NEW_ORDER_ID') 23 | 24 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/orders/{ORDER_ID}' 25 | url_path = urlparse(uri).path 26 | timestamp = str(int(time.time())) 27 | message = timestamp + 'GET' + url_path 28 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 29 | 30 | headers = { 31 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 32 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 33 | 'X-CB-ACCESS-KEY': API_KEY, 34 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 35 | 'Accept': 'application/json' 36 | } 37 | 38 | response = requests.get(uri, headers=headers) 39 | parsed_response = json.loads(response.text) 40 | print(json.dumps(parsed_response, indent=3)) 41 | -------------------------------------------------------------------------------- /REST/prime_get_order_fills.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests, sys 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | try: 24 | order_id = sys.argv[1] 25 | except IndexError: 26 | sys.exit("Please provide order_id as a command line argument.") 27 | 28 | 29 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/orders/{order_id}/fills' 30 | url_path = urlparse(uri).path 31 | timestamp = str(int(time.time())) 32 | message = timestamp + 'GET' + url_path 33 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 34 | 35 | headers = { 36 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 37 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 38 | 'X-CB-ACCESS-KEY': API_KEY, 39 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 40 | 'Accept': 'application/json' 41 | } 42 | 43 | response = requests.get(uri, headers=headers) 44 | parsed_response = json.loads(response.text) 45 | print(json.dumps(parsed_response, indent=3)) 46 | -------------------------------------------------------------------------------- /REST/prime_get_portfolio_by_id.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_get_portfolio_credit_information.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/credit' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_get_transaction.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests, sys 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | try: 24 | transaction_id = sys.argv[1] 25 | except IndexError: 26 | sys.exit("Please provide the transaction ID as a command line argument " 27 | "(e.g. python prime_get_transaction.py ).") 28 | 29 | 30 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/transactions/{transaction_id}' 31 | url_path = urlparse(uri).path 32 | timestamp = str(int(time.time())) 33 | message = timestamp + 'GET' + url_path 34 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 35 | 36 | headers = { 37 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 38 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 39 | 'X-CB-ACCESS-KEY': API_KEY, 40 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 41 | 'Accept': 'application/json' 42 | } 43 | 44 | response = requests.get(uri, headers=headers) 45 | parsed_response = json.loads(response.text) 46 | print(json.dumps(parsed_response, indent=3)) 47 | -------------------------------------------------------------------------------- /REST/prime_get_wallet_balance.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json, hmac, hashlib, time, os, base64, requests 16 | from urllib.parse import urlparse 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | WALLET_ID = os.environ.get('WALLET_ID') 23 | 24 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/wallets/{WALLET_ID}/balance' 25 | url_path = urlparse(uri).path 26 | timestamp = str(int(time.time())) 27 | message = timestamp + 'GET' + url_path 28 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 29 | 30 | headers = { 31 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 32 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 33 | 'X-CB-ACCESS-KEY': API_KEY, 34 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 35 | 'Accept': 'application/json' 36 | } 37 | 38 | response = requests.get(uri, headers=headers) 39 | parsed_response = json.loads(response.text) 40 | print(json.dumps(parsed_response, indent=3)) -------------------------------------------------------------------------------- /REST/prime_get_wallet_by_id.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json, hmac, hashlib, time, uuid, os, base64, requests 16 | from urllib.parse import urlparse 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | WALLET_ID = os.environ.get('WALLET_ID') 23 | 24 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/wallets/{WALLET_ID}' 25 | url_path = urlparse(uri).path 26 | timestamp = str(int(time.time())) 27 | message = timestamp + 'GET' + url_path 28 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 29 | 30 | headers = { 31 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 32 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 33 | 'X-CB-ACCESS-KEY': API_KEY, 34 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 35 | 'Accept': 'application/json' 36 | } 37 | 38 | response = requests.get(uri, headers=headers) 39 | parsed_response = json.loads(response.text) 40 | print(json.dumps(parsed_response, indent=3)) -------------------------------------------------------------------------------- /REST/prime_get_wallet_by_name.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json, hmac, hashlib, time, os, base64, requests 16 | from urllib.parse import urlparse 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | WALLET_NAME = os.environ.get('WALLET_NAME') 23 | 24 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/wallets?type=VAULT&symbols=ETH' 25 | url_path = urlparse(uri).path 26 | timestamp = str(int(time.time())) 27 | message = timestamp + 'GET' + url_path 28 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 29 | 30 | headers = { 31 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 32 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 33 | 'X-CB-ACCESS-KEY': API_KEY, 34 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 35 | 'Accept': 'application/json' 36 | } 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | wallets = parsed_response['wallets'] 40 | 41 | for wallet in wallets: 42 | if wallet['name'] == WALLET_NAME: 43 | destination_wallet_id = wallet['id'] 44 | print(destination_wallet_id) 45 | -------------------------------------------------------------------------------- /REST/prime_get_wallet_deposit_instructions.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json, hmac, hashlib, time, uuid, os, base64, requests, sys 16 | from urllib.parse import urlparse 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | try: 24 | wallet_id = sys.argv[1] 25 | deposit_type = sys.argv[2].upper() 26 | except IndexError: 27 | sys.exit("Please provide wallet_id and deposit_type (e.g. CRYPTO) as command line arguments") 28 | 29 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/wallets/{wallet_id}' \ 30 | f'/deposit_instructions?deposit_type={deposit_type}' 31 | url_path = urlparse(uri).path 32 | timestamp = str(int(time.time())) 33 | message = timestamp + 'GET' + url_path 34 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 35 | 36 | headers = { 37 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 38 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 39 | 'X-CB-ACCESS-KEY': API_KEY, 40 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 41 | 'Accept': 'application/json' 42 | } 43 | response = requests.get(uri, headers=headers) 44 | parsed_response = json.loads(response.text) 45 | print(json.dumps(parsed_response, indent=3)) 46 | -------------------------------------------------------------------------------- /REST/prime_list_activities.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json, hmac, hashlib, time, uuid, os, base64, requests 16 | from urllib.parse import urlparse 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/activities' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | response = requests.get(uri, headers=headers) 37 | parsed_response = json.loads(response.text) 38 | print(json.dumps(parsed_response, indent=3)) 39 | -------------------------------------------------------------------------------- /REST/prime_list_address_book.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json, hmac, hashlib, time, uuid, os, base64, requests 16 | from urllib.parse import urlparse 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/address_book' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | response = requests.get(uri, headers=headers) 37 | parsed_response = json.loads(response.text) 38 | print(json.dumps(parsed_response, indent=3)) 39 | -------------------------------------------------------------------------------- /REST/prime_list_allocations.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import json, hmac, hashlib, time, os, base64, requests 15 | from urllib.parse import urlparse 16 | from dateutil.relativedelta import relativedelta 17 | from datetime import datetime 18 | 19 | API_KEY = os.environ.get('ACCESS_KEY') 20 | SECRET_KEY = os.environ.get('SIGNING_KEY') 21 | PASSPHRASE = os.environ.get('PASSPHRASE') 22 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 23 | 24 | # collect allocations from past three months 25 | time_offset = datetime.now() - relativedelta(months=3) 26 | start_date = time_offset.strftime('%Y-%m-%dT%H:%M:%SZ') 27 | 28 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/allocations?start_date={start_date}' 29 | url_path = urlparse(uri).path 30 | timestamp = str(int(time.time())) 31 | message = timestamp + 'GET' + url_path 32 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 33 | 34 | headers = { 35 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 36 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 37 | 'X-CB-ACCESS-KEY': API_KEY, 38 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 39 | 'Accept': 'application/json' 40 | } 41 | 42 | response = requests.get(uri, headers=headers) 43 | parsed_response = json.loads(response.text) 44 | print(json.dumps(parsed_response, indent=3)) 45 | -------------------------------------------------------------------------------- /REST/prime_list_assets.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | ENTITY_ID = os.environ.get('ENTITY_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/entities/{ENTITY_ID}/assets' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_list_balances.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/balances' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_list_balances_csv.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import csv 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/balances' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | 40 | output_dir = os.getcwd() 41 | output_file = os.path.join(output_dir, 'balances.csv') 42 | 43 | if 'balances' in parsed_response: 44 | balances = parsed_response['balances'] 45 | 46 | columns = balances[0].keys() if balances else [] 47 | 48 | with open(output_file, 'w', newline='') as csvfile: 49 | writer = csv.DictWriter(csvfile, fieldnames=columns) 50 | writer.writeheader() 51 | for balance in balances: 52 | writer.writerow(balance) 53 | 54 | print(f"Data has been written to {output_file}") 55 | -------------------------------------------------------------------------------- /REST/prime_list_entity_activities.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json, hmac, hashlib, time, os, base64, requests 16 | from urllib.parse import urlparse 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | ENTITY_ID = os.environ.get('ENTITY_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/entities/{ENTITY_ID}/activities' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | response = requests.get(uri, headers=headers) 37 | parsed_response = json.loads(response.text) 38 | print(json.dumps(parsed_response, indent=3)) 39 | -------------------------------------------------------------------------------- /REST/prime_list_entity_payment_methods.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | ENTITY_ID = os.environ.get('ENTITY_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/entities/{ENTITY_ID}/payment-methods' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_list_fills.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | start_date = time.strftime("%Y-%m-01T00:00:00Z") 24 | 25 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/fills?start_date={start_date}' 26 | url_path = urlparse(uri).path 27 | timestamp = str(int(time.time())) 28 | message = timestamp + 'GET' + url_path 29 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 30 | 31 | headers = { 32 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 33 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 34 | 'X-CB-ACCESS-KEY': API_KEY, 35 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 36 | 'Accept': 'application/json' 37 | } 38 | 39 | response = requests.get(uri, headers=headers) 40 | parsed_response = json.loads(response.text) 41 | print(json.dumps(parsed_response, indent=3)) 42 | -------------------------------------------------------------------------------- /REST/prime_list_invoices.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | ENTITY_ID = os.environ.get('ENTITY_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/entities/{ENTITY_ID}/invoices' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_list_open_orders.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/open_orders' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_list_orders.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | product_id = 'ETH-USD' 24 | 25 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/orders?product_ids={product_id}&sort_direction=DESC' 26 | url_path = urlparse(uri).path 27 | timestamp = str(int(time.time())) 28 | message = timestamp + 'GET' + url_path 29 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 30 | 31 | headers = { 32 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 33 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 34 | 'X-CB-ACCESS-KEY': API_KEY, 35 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 36 | 'Accept': 'application/json' 37 | } 38 | 39 | response = requests.get(uri, headers=headers) 40 | parsed_response = json.loads(response.text) 41 | print(json.dumps(parsed_response, indent=3)) 42 | -------------------------------------------------------------------------------- /REST/prime_list_payment_methods.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | ENTITY_ID = os.environ.get('ENTITY_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/entities/{ENTITY_ID}/payment-methods' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_list_portfolios.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | 22 | uri = 'https://api.prime.coinbase.com/v1/portfolios' 23 | url_path = urlparse(uri).path 24 | timestamp = str(int(time.time())) 25 | message = timestamp + 'GET' + url_path 26 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 27 | 28 | headers = { 29 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 30 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 31 | 'X-CB-ACCESS-KEY': API_KEY, 32 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 33 | 'Accept': 'application/json' 34 | } 35 | 36 | response = requests.get(uri, headers=headers) 37 | parsed_response = json.loads(response.text) 38 | print(json.dumps(parsed_response, indent=3)) 39 | -------------------------------------------------------------------------------- /REST/prime_list_products.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/products?limit=1000' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_list_transactions.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/transactions' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_list_wallets.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from urllib.parse import urlparse 16 | import json, hmac, hashlib, time, os, base64, requests 17 | 18 | API_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | PASSPHRASE = os.environ.get('PASSPHRASE') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/wallets' 24 | url_path = urlparse(uri).path 25 | timestamp = str(int(time.time())) 26 | message = timestamp + 'GET' + url_path 27 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 28 | 29 | headers = { 30 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 31 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 32 | 'X-CB-ACCESS-KEY': API_KEY, 33 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 34 | 'Accept': 'application/json' 35 | } 36 | 37 | response = requests.get(uri, headers=headers) 38 | parsed_response = json.loads(response.text) 39 | print(json.dumps(parsed_response, indent=3)) 40 | -------------------------------------------------------------------------------- /REST/prime_locate_order_by_client_order_id.py: -------------------------------------------------------------------------------- 1 | from urllib.parse import urlparse 2 | import json, hmac, hashlib, time, os, base64, requests, sys 3 | 4 | if len(sys.argv) < 2: 5 | print('Usage: python prime_locate_order_by_client_order_id.py ') 6 | sys.exit(1) 7 | 8 | client_order_id_to_check = sys.argv[1] 9 | 10 | API_KEY = os.environ.get('ACCESS_KEY') 11 | SECRET_KEY = os.environ.get('SIGNING_KEY') 12 | PASSPHRASE = os.environ.get('PASSPHRASE') 13 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 14 | 15 | 16 | def list_orders(uri): 17 | url_path = urlparse(uri).path 18 | timestamp = str(int(time.time())) 19 | message = timestamp + 'GET' + url_path 20 | signature_b64 = base64.b64encode(hmac.digest(SECRET_KEY.encode(), message.encode(), hashlib.sha256)) 21 | 22 | headers = { 23 | 'X-CB-ACCESS-SIGNATURE': signature_b64, 24 | 'X-CB-ACCESS-TIMESTAMP': timestamp, 25 | 'X-CB-ACCESS-KEY': API_KEY, 26 | 'X-CB-ACCESS-PASSPHRASE': PASSPHRASE, 27 | 'Accept': 'application/json' 28 | } 29 | 30 | response = requests.get(uri, headers=headers) 31 | if response.status_code != 200: 32 | print(f'Failed to list orders: HTTP {response.status_code} - {response.text}') 33 | return None 34 | return json.loads(response.text) 35 | 36 | 37 | def search_order(client_order_id, parsed_response): 38 | for order in parsed_response.get('orders', []): 39 | if order.get('client_order_id') == client_order_id: 40 | return order 41 | return None 42 | 43 | 44 | base_uri = f'https://api.prime.coinbase.com/v1/portfolios/{PORTFOLIO_ID}/orders' 45 | uri = base_uri 46 | 47 | order_found = None 48 | 49 | while True: 50 | parsed_response = list_orders(uri) 51 | if not parsed_response: 52 | break 53 | 54 | order_found = search_order(client_order_id_to_check, parsed_response) 55 | if order_found: 56 | break 57 | 58 | pagination_info = parsed_response.get('pagination', {}) 59 | 60 | if pagination_info.get('has_next'): 61 | next_cursor = pagination_info.get('next_cursor') 62 | uri = f'{base_uri}?cursor={next_cursor}' 63 | else: 64 | break 65 | 66 | if order_found: 67 | print(f'Order found:\n Client Order ID: {client_order_id_to_check}\n Associated Order ID: {order_found.get("id")}') 68 | else: 69 | print(f'Order with client_order_id {client_order_id_to_check} not found.') 70 | -------------------------------------------------------------------------------- /REST/prime_ws_heartbeats.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import asyncio, base64, hashlib, hmac, json, os, sys, time, websockets 16 | 17 | PASSPHRASE = os.environ.get('PASSPHRASE') 18 | ACCESS_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | SVC_ACCOUNTID = os.environ.get('SVC_ACCOUNTID') 21 | 22 | uri = 'wss://ws-feed.prime.coinbase.com' 23 | timestamp = str(int(time.time())) 24 | channel = 'heartbeats' 25 | product_ids = ['ETH-USD'] 26 | 27 | 28 | async def main_loop(): 29 | while True: 30 | try: 31 | async with websockets.connect(uri, ping_interval=None, max_size=None) as websocket: 32 | signature = sign(channel, ACCESS_KEY, SVC_ACCOUNTID, product_ids) 33 | auth_message = json.dumps({ 34 | 'type': 'subscribe', 35 | 'channel': channel, 36 | 'access_key': ACCESS_KEY, 37 | 'api_key_id': SVC_ACCOUNTID, 38 | 'timestamp': timestamp, 39 | 'passphrase': PASSPHRASE, 40 | 'signature': signature, 41 | 'product_ids': product_ids 42 | }) 43 | await websocket.send(auth_message) 44 | while True: 45 | response = await websocket.recv() 46 | parsed_response = json.loads(response) 47 | print(json.dumps(parsed_response, indent=3)) 48 | except websockets.ConnectionClosed: 49 | continue 50 | 51 | 52 | def sign(channel, key, account_id, product_ids): 53 | message = channel + key + account_id + timestamp + "".join(product_ids) 54 | signature = hmac.new(SECRET_KEY.encode('utf-8'), message.encode('utf-8'), digestmod=hashlib.sha256).digest() 55 | signature_b64 = base64.b64encode(signature).decode() 56 | return signature_b64 57 | 58 | 59 | try: 60 | asyncio.get_event_loop().run_until_complete(main_loop()) 61 | except KeyboardInterrupt: 62 | print('\nClosing Prime websocket feed') 63 | sys.exit() 64 | -------------------------------------------------------------------------------- /REST/prime_ws_market.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import asyncio, base64, hashlib, hmac, json, os, sys, time, websockets 16 | 17 | PASSPHRASE = os.environ.get('PASSPHRASE') 18 | ACCESS_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | SVC_ACCOUNTID = os.environ.get('SVC_ACCOUNTID') 21 | 22 | uri = 'wss://ws-feed.prime.coinbase.com' 23 | timestamp = str(int(time.time())) 24 | channel = 'l2_data' 25 | product_ids = ['ETH-USD'] 26 | 27 | 28 | async def main_loop(): 29 | while True: 30 | try: 31 | async with websockets.connect(uri, ping_interval=None, max_size=None) as websocket: 32 | signature = sign(channel, ACCESS_KEY, SVC_ACCOUNTID, product_ids) 33 | auth_message = json.dumps({ 34 | 'type': 'subscribe', 35 | 'channel': channel, 36 | 'access_key': ACCESS_KEY, 37 | 'api_key_id': SVC_ACCOUNTID, 38 | 'timestamp': timestamp, 39 | 'passphrase': PASSPHRASE, 40 | 'signature': signature, 41 | 'product_ids': product_ids 42 | }) 43 | await websocket.send(auth_message) 44 | while True: 45 | response = await websocket.recv() 46 | parsed_response = json.loads(response) 47 | print(json.dumps(parsed_response, indent=3)) 48 | except websockets.ConnectionClosed: 49 | continue 50 | 51 | 52 | def sign(channel, key, account_id, product_ids): 53 | message = channel + key + account_id + timestamp + "".join(product_ids) 54 | signature = hmac.new(SECRET_KEY.encode('utf-8'), message.encode('utf-8'), digestmod=hashlib.sha256).digest() 55 | signature_b64 = base64.b64encode(signature).decode() 56 | return signature_b64 57 | 58 | 59 | try: 60 | asyncio.get_event_loop().run_until_complete(main_loop()) 61 | except KeyboardInterrupt: 62 | print('\nClosing Prime websocket feed') 63 | sys.exit() 64 | -------------------------------------------------------------------------------- /REST/prime_ws_orders.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022-present Coinbase Global, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import asyncio, base64, hashlib, hmac, json, os, sys, time, websockets 16 | 17 | PASSPHRASE = os.environ.get('PASSPHRASE') 18 | ACCESS_KEY = os.environ.get('ACCESS_KEY') 19 | SECRET_KEY = os.environ.get('SIGNING_KEY') 20 | SVC_ACCOUNTID = os.environ.get('SVC_ACCOUNTID') 21 | PORTFOLIO_ID = os.environ.get('PORTFOLIO_ID') 22 | 23 | uri = 'wss://ws-feed.prime.coinbase.com' 24 | timestamp = str(int(time.time())) 25 | channel = 'orders' 26 | product_ids = ['BTC-USD', 'ETH-USD'] 27 | 28 | 29 | async def main_loop(): 30 | while True: 31 | try: 32 | async with websockets.connect(uri, ping_interval=None, max_size=None) as websocket: 33 | signature = sign(channel, ACCESS_KEY, SVC_ACCOUNTID, PORTFOLIO_ID, product_ids) 34 | auth_message = json.dumps({ 35 | 'type': 'subscribe', 36 | 'channel': channel, 37 | 'access_key': ACCESS_KEY, 38 | 'api_key_id': SVC_ACCOUNTID, 39 | 'timestamp': timestamp, 40 | 'passphrase': PASSPHRASE, 41 | 'signature': signature, 42 | 'portfolio_id': PORTFOLIO_ID, 43 | 'product_ids': product_ids 44 | }) 45 | await websocket.send(auth_message) 46 | while True: 47 | response = await websocket.recv() 48 | parsed_response = json.loads(response) 49 | print(json.dumps(parsed_response, indent=3)) 50 | except websockets.ConnectionClosed: 51 | continue 52 | 53 | 54 | def sign(channel, key, account_id, PORTFOLIO_ID, product_ids): 55 | message = channel + key + account_id + timestamp + PORTFOLIO_ID + "".join(product_ids) 56 | signature = hmac.new(SECRET_KEY.encode('utf-8'), message.encode('utf-8'), digestmod=hashlib.sha256).digest() 57 | signature_b64 = base64.b64encode(signature).decode() 58 | return signature_b64 59 | 60 | 61 | try: 62 | asyncio.get_event_loop().run_until_complete(main_loop()) 63 | except KeyboardInterrupt: 64 | print('\nClosing Prime websocket feed') 65 | sys.exit() 66 | -------------------------------------------------------------------------------- /REST/requirements.txt: -------------------------------------------------------------------------------- 1 | websockets==11.0.3 2 | requests==2.32.0 3 | -------------------------------------------------------------------------------- /THIRD-PARTY-NOTICES: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------- 2 | License notice for websockets 3 | --------------------------------------------------------------------- 4 | 5 | Copyright (c) 2013-2021 Aymeric Augustin and contributors. 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | * Neither the name of websockets nor the names of its contributors may 17 | be used to endorse or promote products derived from this software without 18 | specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | --------------------------------------------------------------------- 32 | License notice for requeests 33 | --------------------------------------------------------------------- 34 | 35 | Apache License 36 | Version 2.0, January 2004 37 | http://www.apache.org/licenses/ 38 | 39 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 40 | 41 | 1. Definitions. 42 | 43 | "License" shall mean the terms and conditions for use, reproduction, 44 | and distribution as defined by Sections 1 through 9 of this document. 45 | 46 | "Licensor" shall mean the copyright owner or entity authorized by 47 | the copyright owner that is granting the License. 48 | 49 | "Legal Entity" shall mean the union of the acting entity and all 50 | other entities that control, are controlled by, or are under common 51 | control with that entity. For the purposes of this definition, 52 | "control" means (i) the power, direct or indirect, to cause the 53 | direction or management of such entity, whether by contract or 54 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 55 | outstanding shares, or (iii) beneficial ownership of such entity. 56 | 57 | "You" (or "Your") shall mean an individual or Legal Entity 58 | exercising permissions granted by this License. 59 | 60 | "Source" form shall mean the preferred form for making modifications, 61 | including but not limited to software source code, documentation 62 | source, and configuration files. 63 | 64 | "Object" form shall mean any form resulting from mechanical 65 | transformation or translation of a Source form, including but 66 | not limited to compiled object code, generated documentation, 67 | and conversions to other media types. 68 | 69 | "Work" shall mean the work of authorship, whether in Source or 70 | Object form, made available under the License, as indicated by a 71 | copyright notice that is included in or attached to the work 72 | (an example is provided in the Appendix below). 73 | 74 | "Derivative Works" shall mean any work, whether in Source or Object 75 | form, that is based on (or derived from) the Work and for which the 76 | editorial revisions, annotations, elaborations, or other modifications 77 | represent, as a whole, an original work of authorship. For the purposes 78 | of this License, Derivative Works shall not include works that remain 79 | separable from, or merely link (or bind by name) to the interfaces of, 80 | the Work and Derivative Works thereof. 81 | 82 | "Contribution" shall mean any work of authorship, including 83 | the original version of the Work and any modifications or additions 84 | to that Work or Derivative Works thereof, that is intentionally 85 | submitted to Licensor for inclusion in the Work by the copyright owner 86 | or by an individual or Legal Entity authorized to submit on behalf of 87 | the copyright owner. For the purposes of this definition, "submitted" 88 | means any form of electronic, verbal, or written communication sent 89 | to the Licensor or its representatives, including but not limited to 90 | communication on electronic mailing lists, source code control systems, 91 | and issue tracking systems that are managed by, or on behalf of, the 92 | Licensor for the purpose of discussing and improving the Work, but 93 | excluding communication that is conspicuously marked or otherwise 94 | designated in writing by the copyright owner as "Not a Contribution." 95 | 96 | "Contributor" shall mean Licensor and any individual or Legal Entity 97 | on behalf of whom a Contribution has been received by Licensor and 98 | subsequently incorporated within the Work. 99 | 100 | 2. Grant of Copyright License. Subject to the terms and conditions of 101 | this License, each Contributor hereby grants to You a perpetual, 102 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 103 | copyright license to reproduce, prepare Derivative Works of, 104 | publicly display, publicly perform, sublicense, and distribute the 105 | Work and such Derivative Works in Source or Object form. 106 | 107 | 3. Grant of Patent License. Subject to the terms and conditions of 108 | this License, each Contributor hereby grants to You a perpetual, 109 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 110 | (except as stated in this section) patent license to make, have made, 111 | use, offer to sell, sell, import, and otherwise transfer the Work, 112 | where such license applies only to those patent claims licensable 113 | by such Contributor that are necessarily infringed by their 114 | Contribution(s) alone or by combination of their Contribution(s) 115 | with the Work to which such Contribution(s) was submitted. If You 116 | institute patent litigation against any entity (including a 117 | cross-claim or counterclaim in a lawsuit) alleging that the Work 118 | or a Contribution incorporated within the Work constitutes direct 119 | or contributory patent infringement, then any patent licenses 120 | granted to You under this License for that Work shall terminate 121 | as of the date such litigation is filed. 122 | 123 | 4. Redistribution. You may reproduce and distribute copies of the 124 | Work or Derivative Works thereof in any medium, with or without 125 | modifications, and in Source or Object form, provided that You 126 | meet the following conditions: 127 | 128 | (a) You must give any other recipients of the Work or 129 | Derivative Works a copy of this License; and 130 | 131 | (b) You must cause any modified files to carry prominent notices 132 | stating that You changed the files; and 133 | 134 | (c) You must retain, in the Source form of any Derivative Works 135 | that You distribute, all copyright, patent, trademark, and 136 | attribution notices from the Source form of the Work, 137 | excluding those notices that do not pertain to any part of 138 | the Derivative Works; and 139 | 140 | (d) If the Work includes a "NOTICE" text file as part of its 141 | distribution, then any Derivative Works that You distribute must 142 | include a readable copy of the attribution notices contained 143 | within such NOTICE file, excluding those notices that do not 144 | pertain to any part of the Derivative Works, in at least one 145 | of the following places: within a NOTICE text file distributed 146 | as part of the Derivative Works; within the Source form or 147 | documentation, if provided along with the Derivative Works; or, 148 | within a display generated by the Derivative Works, if and 149 | wherever such third-party notices normally appear. The contents 150 | of the NOTICE file are for informational purposes only and 151 | do not modify the License. You may add Your own attribution 152 | notices within Derivative Works that You distribute, alongside 153 | or as an addendum to the NOTICE text from the Work, provided 154 | that such additional attribution notices cannot be construed 155 | as modifying the License. 156 | 157 | You may add Your own copyright statement to Your modifications and 158 | may provide additional or different license terms and conditions 159 | for use, reproduction, or distribution of Your modifications, or 160 | for any such Derivative Works as a whole, provided Your use, 161 | reproduction, and distribution of the Work otherwise complies with 162 | the conditions stated in this License. 163 | 164 | 5. Submission of Contributions. Unless You explicitly state otherwise, 165 | any Contribution intentionally submitted for inclusion in the Work 166 | by You to the Licensor shall be under the terms and conditions of 167 | this License, without any additional terms or conditions. 168 | Notwithstanding the above, nothing herein shall supersede or modify 169 | the terms of any separate license agreement you may have executed 170 | with Licensor regarding such Contributions. 171 | 172 | 6. Trademarks. This License does not grant permission to use the trade 173 | names, trademarks, service marks, or product names of the Licensor, 174 | except as required for reasonable and customary use in describing the 175 | origin of the Work and reproducing the content of the NOTICE file. 176 | 177 | 7. Disclaimer of Warranty. Unless required by applicable law or 178 | agreed to in writing, Licensor provides the Work (and each 179 | Contributor provides its Contributions) on an "AS IS" BASIS, 180 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 181 | implied, including, without limitation, any warranties or conditions 182 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 183 | PARTICULAR PURPOSE. You are solely responsible for determining the 184 | appropriateness of using or redistributing the Work and assume any 185 | risks associated with Your exercise of permissions under this License. 186 | 187 | 8. Limitation of Liability. In no event and under no legal theory, 188 | whether in tort (including negligence), contract, or otherwise, 189 | unless required by applicable law (such as deliberate and grossly 190 | negligent acts) or agreed to in writing, shall any Contributor be 191 | liable to You for damages, including any direct, indirect, special, 192 | incidental, or consequential damages of any character arising as a 193 | result of this License or out of the use or inability to use the 194 | Work (including but not limited to damages for loss of goodwill, 195 | work stoppage, computer failure or malfunction, or any and all 196 | other commercial damages or losses), even if such Contributor 197 | has been advised of the possibility of such damages. 198 | 199 | 9. Accepting Warranty or Additional Liability. While redistributing 200 | the Work or Derivative Works thereof, You may choose to offer, 201 | and charge a fee for, acceptance of support, warranty, indemnity, 202 | or other liability obligations and/or rights consistent with this 203 | License. However, in accepting such obligations, You may act only 204 | on Your own behalf and on Your sole responsibility, not on behalf 205 | of any other Contributor, and only if You agree to indemnify, 206 | defend, and hold each Contributor harmless for any liability 207 | incurred by, or claims asserted against, such Contributor by reason 208 | of your accepting any such warranty or additional liability. 209 | 210 | --------------------------------------------------------------------- 211 | --------------------------------------------------------------------- 212 | License notice for Quickfix 213 | --------------------------------------------------------------------- 214 | 215 | Copyright (c) 2001-2018 Oren Miller 216 | 217 | Redistribution and use in source and binary forms, with or without 218 | modification, are permitted provided that the following conditions 219 | are met: 220 | 221 | 1. Redistributions of source code must retain the above copyright 222 | notice, this list of conditions and the following disclaimer. 223 | 224 | 2. Redistributions in binary form must reproduce the above copyright 225 | notice, this list of conditions and the following disclaimer in 226 | the documentation and/or other materials provided with the 227 | distribution. 228 | 229 | 3. The end-user documentation included with the redistribution, 230 | if any, must include the following acknowledgment: 231 | "This product includes software developed by 232 | quickfixengine.org (http://www.quickfixengine.org/)." 233 | Alternately, this acknowledgment may appear in the software itself, 234 | if and wherever such third-party acknowledgments normally appear. 235 | 236 | 4. The names "QuickFIX" and "quickfixengine.org" must 237 | not be used to endorse or promote products derived from this 238 | software without prior written permission. For written 239 | permission, please contact ask@quickfixengine.org 240 | 241 | 5. Products derived from this software may not be called "QuickFIX", 242 | nor may "QuickFIX" appear in their name, without prior written 243 | permission of quickfixengine.org 244 | 245 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 246 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 247 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 248 | DISCLAIMED. IN NO EVENT SHALL QUICKFIXENGINE.ORG OR 249 | ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 250 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 251 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 252 | USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 253 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 254 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 255 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 256 | SUCH DAMAGE. 257 | 258 | --------------------------------------------------------------------- 259 | License notice for certifi 260 | --------------------------------------------------------------------- 261 | 262 | Mozilla Public License Version 2.0 263 | ================================== 264 | 265 | 1. Definitions 266 | -------------- 267 | 268 | 1.1. "Contributor" 269 | means each individual or legal entity that creates, contributes to 270 | the creation of, or owns Covered Software. 271 | 272 | 1.2. "Contributor Version" 273 | means the combination of the Contributions of others (if any) used 274 | by a Contributor and that particular Contributor's Contribution. 275 | 276 | 1.3. "Contribution" 277 | means Covered Software of a particular Contributor. 278 | 279 | 1.4. "Covered Software" 280 | means Source Code Form to which the initial Contributor has attached 281 | the notice in Exhibit A, the Executable Form of such Source Code 282 | Form, and Modifications of such Source Code Form, in each case 283 | including portions thereof. 284 | 285 | 1.5. "Incompatible With Secondary Licenses" 286 | means 287 | 288 | (a) that the initial Contributor has attached the notice described 289 | in Exhibit B to the Covered Software; or 290 | 291 | (b) that the Covered Software was made available under the terms of 292 | version 1.1 or earlier of the License, but not also under the 293 | terms of a Secondary License. 294 | 295 | 1.6. "Executable Form" 296 | means any form of the work other than Source Code Form. 297 | 298 | 1.7. "Larger Work" 299 | means a work that combines Covered Software with other material, in 300 | a separate file or files, that is not Covered Software. 301 | 302 | 1.8. "License" 303 | means this document. 304 | 305 | 1.9. "Licensable" 306 | means having the right to grant, to the maximum extent possible, 307 | whether at the time of the initial grant or subsequently, any and 308 | all of the rights conveyed by this License. 309 | 310 | 1.10. "Modifications" 311 | means any of the following: 312 | 313 | (a) any file in Source Code Form that results from an addition to, 314 | deletion from, or modification of the contents of Covered 315 | Software; or 316 | 317 | (b) any new file in Source Code Form that contains any Covered 318 | Software. 319 | 320 | 1.11. "Patent Claims" of a Contributor 321 | means any patent claim(s), including without limitation, method, 322 | process, and apparatus claims, in any patent Licensable by such 323 | Contributor that would be infringed, but for the grant of the 324 | License, by the making, using, selling, offering for sale, having 325 | made, import, or transfer of either its Contributions or its 326 | Contributor Version. 327 | 328 | 1.12. "Secondary License" 329 | means either the GNU General Public License, Version 2.0, the GNU 330 | Lesser General Public License, Version 2.1, the GNU Affero General 331 | Public License, Version 3.0, or any later versions of those 332 | licenses. 333 | 334 | 1.13. "Source Code Form" 335 | means the form of the work preferred for making modifications. 336 | 337 | 1.14. "You" (or "Your") 338 | means an individual or a legal entity exercising rights under this 339 | License. For legal entities, "You" includes any entity that 340 | controls, is controlled by, or is under common control with You. For 341 | purposes of this definition, "control" means (a) the power, direct 342 | or indirect, to cause the direction or management of such entity, 343 | whether by contract or otherwise, or (b) ownership of more than 344 | fifty percent (50%) of the outstanding shares or beneficial 345 | ownership of such entity. 346 | 347 | 2. License Grants and Conditions 348 | -------------------------------- 349 | 350 | 2.1. Grants 351 | 352 | Each Contributor hereby grants You a world-wide, royalty-free, 353 | non-exclusive license: 354 | 355 | (a) under intellectual property rights (other than patent or trademark) 356 | Licensable by such Contributor to use, reproduce, make available, 357 | modify, display, perform, distribute, and otherwise exploit its 358 | Contributions, either on an unmodified basis, with Modifications, or 359 | as part of a Larger Work; and 360 | 361 | (b) under Patent Claims of such Contributor to make, use, sell, offer 362 | for sale, have made, import, and otherwise transfer either its 363 | Contributions or its Contributor Version. 364 | 365 | 2.2. Effective Date 366 | 367 | The licenses granted in Section 2.1 with respect to any Contribution 368 | become effective for each Contribution on the date the Contributor first 369 | distributes such Contribution. 370 | 371 | 2.3. Limitations on Grant Scope 372 | 373 | The licenses granted in this Section 2 are the only rights granted under 374 | this License. No additional rights or licenses will be implied from the 375 | distribution or licensing of Covered Software under this License. 376 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 377 | Contributor: 378 | 379 | (a) for any code that a Contributor has removed from Covered Software; 380 | or 381 | 382 | (b) for infringements caused by: (i) Your and any other third party's 383 | modifications of Covered Software, or (ii) the combination of its 384 | Contributions with other software (except as part of its Contributor 385 | Version); or 386 | 387 | (c) under Patent Claims infringed by Covered Software in the absence of 388 | its Contributions. 389 | 390 | This License does not grant any rights in the trademarks, service marks, 391 | or logos of any Contributor (except as may be necessary to comply with 392 | the notice requirements in Section 3.4). 393 | 394 | 2.4. Subsequent Licenses 395 | 396 | No Contributor makes additional grants as a result of Your choice to 397 | distribute the Covered Software under a subsequent version of this 398 | License (see Section 10.2) or under the terms of a Secondary License (if 399 | permitted under the terms of Section 3.3). 400 | 401 | 2.5. Representation 402 | 403 | Each Contributor represents that the Contributor believes its 404 | Contributions are its original creation(s) or it has sufficient rights 405 | to grant the rights to its Contributions conveyed by this License. 406 | 407 | 2.6. Fair Use 408 | 409 | This License is not intended to limit any rights You have under 410 | applicable copyright doctrines of fair use, fair dealing, or other 411 | equivalents. 412 | 413 | 2.7. Conditions 414 | 415 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 416 | in Section 2.1. 417 | 418 | 3. Responsibilities 419 | ------------------- 420 | 421 | 3.1. Distribution of Source Form 422 | 423 | All distribution of Covered Software in Source Code Form, including any 424 | Modifications that You create or to which You contribute, must be under 425 | the terms of this License. You must inform recipients that the Source 426 | Code Form of the Covered Software is governed by the terms of this 427 | License, and how they can obtain a copy of this License. You may not 428 | attempt to alter or restrict the recipients' rights in the Source Code 429 | Form. 430 | 431 | 3.2. Distribution of Executable Form 432 | 433 | If You distribute Covered Software in Executable Form then: 434 | 435 | (a) such Covered Software must also be made available in Source Code 436 | Form, as described in Section 3.1, and You must inform recipients of 437 | the Executable Form how they can obtain a copy of such Source Code 438 | Form by reasonable means in a timely manner, at a charge no more 439 | than the cost of distribution to the recipient; and 440 | 441 | (b) You may distribute such Executable Form under the terms of this 442 | License, or sublicense it under different terms, provided that the 443 | license for the Executable Form does not attempt to limit or alter 444 | the recipients' rights in the Source Code Form under this License. 445 | 446 | 3.3. Distribution of a Larger Work 447 | 448 | You may create and distribute a Larger Work under terms of Your choice, 449 | provided that You also comply with the requirements of this License for 450 | the Covered Software. If the Larger Work is a combination of Covered 451 | Software with a work governed by one or more Secondary Licenses, and the 452 | Covered Software is not Incompatible With Secondary Licenses, this 453 | License permits You to additionally distribute such Covered Software 454 | under the terms of such Secondary License(s), so that the recipient of 455 | the Larger Work may, at their option, further distribute the Covered 456 | Software under the terms of either this License or such Secondary 457 | License(s). 458 | 459 | 3.4. Notices 460 | 461 | You may not remove or alter the substance of any license notices 462 | (including copyright notices, patent notices, disclaimers of warranty, 463 | or limitations of liability) contained within the Source Code Form of 464 | the Covered Software, except that You may alter any license notices to 465 | the extent required to remedy known factual inaccuracies. 466 | 467 | 3.5. Application of Additional Terms 468 | 469 | You may choose to offer, and to charge a fee for, warranty, support, 470 | indemnity or liability obligations to one or more recipients of Covered 471 | Software. However, You may do so only on Your own behalf, and not on 472 | behalf of any Contributor. You must make it absolutely clear that any 473 | such warranty, support, indemnity, or liability obligation is offered by 474 | You alone, and You hereby agree to indemnify every Contributor for any 475 | liability incurred by such Contributor as a result of warranty, support, 476 | indemnity or liability terms You offer. You may include additional 477 | disclaimers of warranty and limitations of liability specific to any 478 | jurisdiction. 479 | 480 | 4. Inability to Comply Due to Statute or Regulation 481 | --------------------------------------------------- 482 | 483 | If it is impossible for You to comply with any of the terms of this 484 | License with respect to some or all of the Covered Software due to 485 | statute, judicial order, or regulation then You must: (a) comply with 486 | the terms of this License to the maximum extent possible; and (b) 487 | describe the limitations and the code they affect. Such description must 488 | be placed in a text file included with all distributions of the Covered 489 | Software under this License. Except to the extent prohibited by statute 490 | or regulation, such description must be sufficiently detailed for a 491 | recipient of ordinary skill to be able to understand it. 492 | 493 | 5. Termination 494 | -------------- 495 | 496 | 5.1. The rights granted under this License will terminate automatically 497 | if You fail to comply with any of its terms. However, if You become 498 | compliant, then the rights granted under this License from a particular 499 | Contributor are reinstated (a) provisionally, unless and until such 500 | Contributor explicitly and finally terminates Your grants, and (b) on an 501 | ongoing basis, if such Contributor fails to notify You of the 502 | non-compliance by some reasonable means prior to 60 days after You have 503 | come back into compliance. Moreover, Your grants from a particular 504 | Contributor are reinstated on an ongoing basis if such Contributor 505 | notifies You of the non-compliance by some reasonable means, this is the 506 | first time You have received notice of non-compliance with this License 507 | from such Contributor, and You become compliant prior to 30 days after 508 | Your receipt of the notice. 509 | 510 | 5.2. If You initiate litigation against any entity by asserting a patent 511 | infringement claim (excluding declaratory judgment actions, 512 | counter-claims, and cross-claims) alleging that a Contributor Version 513 | directly or indirectly infringes any patent, then the rights granted to 514 | You by any and all Contributors for the Covered Software under Section 515 | 2.1 of this License shall terminate. 516 | 517 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 518 | end user license agreements (excluding distributors and resellers) which 519 | have been validly granted by You or Your distributors under this License 520 | prior to termination shall survive termination. 521 | 522 | ************************************************************************ 523 | * * 524 | * 6. Disclaimer of Warranty * 525 | * ------------------------- * 526 | * * 527 | * Covered Software is provided under this License on an "as is" * 528 | * basis, without warranty of any kind, either expressed, implied, or * 529 | * statutory, including, without limitation, warranties that the * 530 | * Covered Software is free of defects, merchantable, fit for a * 531 | * particular purpose or non-infringing. The entire risk as to the * 532 | * quality and performance of the Covered Software is with You. * 533 | * Should any Covered Software prove defective in any respect, You * 534 | * (not any Contributor) assume the cost of any necessary servicing, * 535 | * repair, or correction. This disclaimer of warranty constitutes an * 536 | * essential part of this License. No use of any Covered Software is * 537 | * authorized under this License except under this disclaimer. * 538 | * * 539 | ************************************************************************ 540 | 541 | ************************************************************************ 542 | * * 543 | * 7. Limitation of Liability * 544 | * -------------------------- * 545 | * * 546 | * Under no circumstances and under no legal theory, whether tort * 547 | * (including negligence), contract, or otherwise, shall any * 548 | * Contributor, or anyone who distributes Covered Software as * 549 | * permitted above, be liable to You for any direct, indirect, * 550 | * special, incidental, or consequential damages of any character * 551 | * including, without limitation, damages for lost profits, loss of * 552 | * goodwill, work stoppage, computer failure or malfunction, or any * 553 | * and all other commercial damages or losses, even if such party * 554 | * shall have been informed of the possibility of such damages. This * 555 | * limitation of liability shall not apply to liability for death or * 556 | * personal injury resulting from such party's negligence to the * 557 | * extent applicable law prohibits such limitation. Some * 558 | * jurisdictions do not allow the exclusion or limitation of * 559 | * incidental or consequential damages, so this exclusion and * 560 | * limitation may not apply to You. * 561 | * * 562 | ************************************************************************ 563 | 564 | 8. Litigation 565 | ------------- 566 | 567 | Any litigation relating to this License may be brought only in the 568 | courts of a jurisdiction where the defendant maintains its principal 569 | place of business and such litigation shall be governed by laws of that 570 | jurisdiction, without reference to its conflict-of-law provisions. 571 | Nothing in this Section shall prevent a party's ability to bring 572 | cross-claims or counter-claims. 573 | 574 | 9. Miscellaneous 575 | ---------------- 576 | 577 | This License represents the complete agreement concerning the subject 578 | matter hereof. If any provision of this License is held to be 579 | unenforceable, such provision shall be reformed only to the extent 580 | necessary to make it enforceable. Any law or regulation which provides 581 | that the language of a contract shall be construed against the drafter 582 | shall not be used to construe this License against a Contributor. 583 | 584 | 10. Versions of the License 585 | --------------------------- 586 | 587 | 10.1. New Versions 588 | 589 | Mozilla Foundation is the license steward. Except as provided in Section 590 | 10.3, no one other than the license steward has the right to modify or 591 | publish new versions of this License. Each version will be given a 592 | distinguishing version number. 593 | 594 | 10.2. Effect of New Versions 595 | 596 | You may distribute the Covered Software under the terms of the version 597 | of the License under which You originally received the Covered Software, 598 | or under the terms of any subsequent version published by the license 599 | steward. 600 | 601 | 10.3. Modified Versions 602 | 603 | If you create software not governed by this License, and you want to 604 | create a new license for such software, you may create and use a 605 | modified version of this License if you rename the license and remove 606 | any references to the name of the license steward (except to note that 607 | such modified license differs from this License). 608 | 609 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 610 | Licenses 611 | 612 | If You choose to distribute Source Code Form that is Incompatible With 613 | Secondary Licenses under the terms of this version of the License, the 614 | notice described in Exhibit B of this License must be attached. 615 | 616 | Exhibit A - Source Code Form License Notice 617 | ------------------------------------------- 618 | 619 | This Source Code Form is subject to the terms of the Mozilla Public 620 | License, v. 2.0. If a copy of the MPL was not distributed with this 621 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 622 | 623 | If it is not possible or desirable to put the notice in a particular 624 | file, then You may include the notice in a location (such as a LICENSE 625 | file in a relevant directory) where a recipient would be likely to look 626 | for such a notice. 627 | 628 | You may add additional accurate notices of copyright ownership. 629 | 630 | Exhibit B - "Incompatible With Secondary Licenses" Notice 631 | --------------------------------------------------------- 632 | 633 | This Source Code Form is "Incompatible With Secondary Licenses", as 634 | defined by the Mozilla Public License, v. 2.0. 635 | 636 | --------------------------------------------------------------------- --------------------------------------------------------------------------------