A journey to find a way to programmatically short crypto from the US, you’d think this would be simple… think again!
Exchanges are everywhere… Coinbase, Binance, Gemini, Robinhood, Kraken, eToro, Crypto.com, TradeStation, Coinmama, …
and those with an API… Binance, Bittrex, Poloniex, Coinbase, Kraken, BitFinex, Bitstamp, Hitbtc, BitForex, …
and even fewer offer Short trading from a 🇺🇸 IP address. So are there exchanges that offer short trading via API for US customers? Binance.us does not offer short trading to US based customers.
It is confusing and in flux!
Earlier this year I went searching for an answer.
My criteria was quite simple:
- must be legit for US users, no VPN hacking to pretend to live elsewhere
- must have API into their exchange
- must allow for short selling (margin trading)
- nice if they have solid customer support chat/email
Why? Because my crypto-quant rig wants to short as part of its strategy and it cannot do that on Binance.us, at least not as of this writing.
Many of the exchanges above do not tell you clearly whether or not they serve US customers until you try to register. That is a real pain!
Others do allow US IP addresses but don’t offer short positions, and again not easy to tell and as of the date of this piece it’s a moving target.
Some of these exchanges have horrendous fees, eToro (best to avoid this) charges a ‘no usage’ fee for an account that hasn’t been logged into over some period of time. ⏰ 💵 What?
Other exchanges like BitForex (avoid this one also) have a ‘chat room’ for support where thousands of users are ‘voicing their opinion’. After multiple days of trying to understand how to short via API and getting crazy responses I gave up. 🐒 What?
The reality is that most exchanges today are not geared for developers and quant types, why should they be? That’s not the fat part of the market.
Finally after quite a bit of work I found CoinMetro… based in Tallinn Estonia.
Here’s a primer on this exchange and their rate sheet. Sign up is straight-forward, US users have to authenticate and provide verified ID.
Get discounts, positive vibes and good karma by using my referral code to signup: https://coinmetro.com/?ref=georgek
Be patient as the ID verification is done by their support teams. Crypto can be transferred into your account once verified.
CoinMetro signup here.
Once you are registered you can go to their ‘Exchange’ dashboard and to their ‘Margin’ dashboard…
It’s not intuitive but you can SCROLL DOWN to see the margin collateral section of the dashboard:
Above is an example of ~US$500 applied to margin collateral. Use the slider to set the amount from your wallet. You can easy retrieve this margin collateral (again with the slider) after getting out of margin positions.
The fees for margin trades are significant, 0.20% of the trade value for a short and buy round-trip… Compare this to 0.15% round-trip for Long position on Binance.us (using BNB for fees).
Note the (0.20%) shown in the margin dashboard is for round-trip position, for the total of the open and close of the margin position.
In addition there are margin ‘borrowing fees’…
Interest 0.08222% daily — calculated every 4 hours on borrowed margin
Let’s work this out in a scenario, let’s imagine you take a margin position for USD 100, hold it for 48hours and then close it, the fees would be:
- commission: 100*0.2% … $0.20
- interest: 0.08222 x 100 *2 … $0.17
Total fees for this trade: $0.57 (0.37%)
Another scenario, let’s imagine you take a margin position for EUR 10000, hold it for 10days and then close it, the fees would be:
- commission: 10000*0.2% … EUR 20,00
- interest: 0.08222 x 10000 *10 … EUR 82,00
Total fees for this trade: EUR 102,00 (1.02%)
Watch and account for commissions carefully, as usual.
The commission is taken from the trade, a market buy order of that amount in XCM (the utility token for fees at CoinMetro), creating more volume and demand for the token.
Commission fees are seen in the “Order History” display under “Fees”:
You can also collect ‘rebates’ on fees by holding the CoinMetro coin: XCM
The folks in the Telegram chat group tell me that the ‘trading floor’ of XCM is set to USD 15cents, ie. it cannot be traded for less than that. As of this article its price is 22cents so that is interesting.
Here’s the link to CoinMetro’s API in Postman: https://documenter.getpostman.com/view/3653795/SVfWN6KS
You can experiment with the Postman REST API interface. Then select a language in the upper drop-down list to see example code in that style.
Found a Python wrapper for the CoinMetro REST api here:
Just copy CMapi.py into your working directory and import it, simple. No need to install anything, this is just a thin wrapper. The Authentication wrapper is included and helpful.
Let’s start with some basic imports:
import CMapi
from datetime import datetime, timedelta
import json
import requests
And a client initialization function with your credentials:
client = CMapi.CMClient(email='YOUREMAIL@somewhere.com', passwd='YOURPASSWORD', hashkey='Yes')
Now we can get trading assets:
client.get_trading_assets()[{'name': 'Bitcoin',
'symbol': 'BTC',
'type': 'coin',
'canDeposit': True,
'canWithdraw': True,
'canTrade': True,
'sentimentData': {'sentiment': 32.276666666666664,
'interest': 0.8021655707519841},
'digits': 6,
'minQty': 0.00025,
'maxSwap': 2500,
'canMarket': True,
'id': None},...
Your account balances:
balances = client.get_balances(){'ETH': {'ETH': 0, 'EUR': -0.07, 'BTC': -2e-06, 'USD': -0.09},
'USD': {'USD': 494.66, 'EUR': 419.33, 'BTC': 0.01066, 'ETH': 0.1537},
'XCM': {'XCM': 0, 'EUR': 0, 'BTC': 0, 'USD': 0, 'ETH': 0},
'TOTAL': {'EUR': 419.33, 'BTC': 0.01066, 'USD': 494.66, 'ETH': 0.1537},
'REF': {'XCM': 0, 'EUR': 0, 'BTC': 5e-06, 'USD': 0, 'ETH': 0}}
Get historical data:
now = datetime.now() — timedelta(minutes= 3)candles = client.get_historical_prices(pair=’ETHUSD’, timeframe=60000, From=now.strftime(‘%s’)+’000')for c in candles[‘candleHistory’]:
print(datetime.fromtimestamp(c[‘timestamp’]/1000.0), c[‘o’], c[‘c’])2021-08-15 16:44:00 3249.6723259755 3249.6723259755
2021-08-15 16:45:00 3249.6723259755 3249.6723259755
2021-08-15 16:46:00 3249.6723259755 3249.4520935
2021-08-15 16:47:00 3249.6723259755 3247.57055175
And more, see CMapi.py for details.
The REST API has margin trading endpoints but unfortunately the Python wrapper did not (at the time of this piece), so we resort to making REST requests.
Create Order
Here’s an example of a SHORT Market order via REST API:
BASE = "https://api.coinmetro.com"# sell SHORT on margin
headers={"Authorization":client.bearerToken, 'Content-Type': 'application/x-www-form-urlencoded'}payload = f'orderType=market&buyingCurrency=USD&sellingCurrency=ETH&sellingQty=0.0315&margin=true'response = requests.request("POST", f'{BASE}/exchange/orders/create', headers=headers, data = payload)
responseJson = json.loads(response._content)
Replace the currency and Qty with your variables.
You can also package the parameters in JSON structure.
Note the margin=true parameter, also you must allocate margin collateral (in the dashboard) prior to trying to trade on margin using the API.
The response payload is something like:
{'userID': '60e8fc89116db05a7fdb857b', 'orderID': '60e8fc89116db05a7fdb857b1629051520858cb64815e410cbbac', 'orderType': 'market', 'buyingCurrency': 'USD', 'sellingCurrency': 'ETH', 'sellingQty': 0.0315, 'margin': 'true', 'timeInForce': 4, 'boughtQty': 99.824, 'soldQty': 0.0315, 'creationTime': 1629051520860, 'seqNumber': 5018778582, 'firstFillTime': 1629051520860, 'lastFillTime': 1629051520860, 'fills': [{'seqNumber': 5018778581, 'timestamp': 1629051520860, 'qty': 0.0315, 'price': 3169.015873015873, 'side': 'sell'}], 'completionTime': 1629051520860, 'takerQty': 99.824}
Note the ‘takerQty’, this is the USD amount of margin collateral in USD this transaction took.
Get Orders
You can get a list of filled orders since some period of time:
now = datetime.now() — timedelta(hours=5)
nowInt = int(now.strftime(‘%s’)+’000')fills = client.get_order_fills(since=nowInt)[{'pair': 'ETHUSD',
'seqNumber': 5018778581,
'timestamp': 1629051520860,
'qty': 0.0315,
'price': 3169.015873015873,
'side': 'sell',
'orderID': '60e8fc89116db05a7fdb857b1629051520858cb64815e410cbbac'},
{'pair': 'ETHUSD',
'seqNumber': 5018888387,
'timestamp': 1629051959955,
'qty': 0.031454,
'price': 3173.6504101227188,
'side': 'buy',
'orderID': '60e8fc89116db05a7fdb857b16290519599523046b30d3585a5d7'}]
Notice the ‘qty’ and ‘price’ elements. You can use qty * price to get the amount of currency and Buy a position, as follows:
BASE = "https://api.coinmetro.com"qty = short[‘price’]*short[‘qty’]# buy (close short position)
headers={“Authorization”:client.bearerToken, ‘Content-Type’: ‘application/x-www-form-urlencoded’}payload = f’orderType=market&buyingCurrency=ETH&sellingCurrency=USD&sellingQty=’+qty+’&margin=true’
response = requests.request(“POST”, f’{BASE}/exchange/orders/create’, headers=headers, data = payload)
responseJson = json.loads(response._content)
{'userID': '60e8fc89116db05a7fdb857b',
'orderID': '60e8fc89116db05a7fdb857b162911944571101e1277f9d9f8be1',
'orderType': 'market',
'buyingCurrency': 'ETH',
'sellingCurrency': 'USD',
'sellingQty': 99.943,
'margin': 'true',
'timeInForce': 4,
'boughtQty': 0.030455,
'soldQty': 99.943,
'creationTime': 1629119445720,
'seqNumber': 5036606277,
'firstFillTime': 1629119445721,
'lastFillTime': 1629119445721,
'fills': [{'seqNumber': 5036606276,
'timestamp': 1629119445721,
'qty': 0.030455,
'price': 3281.6614677392877,
'side': 'buy'}],
'completionTime': 1629119445721,
'takerQty': 0.030455}
And finally to Close an existing (filled) position we first need its orderID:
now = datetime.now() — timedelta(days=1)
nowInt = int(now.strftime(‘%s’)+’000')
fills = client.get_order_fills(since=nowInt)
Close position
Let’s close the most recent (filled) order:
# close position# get the most recent filled order
s = fills[-1]headers={“Authorization”:client.bearerToken, ‘Content-Type’: ‘application/x-www-form-urlencoded’}
payload = {}response = requests.request(“POST”, f’{COINMETRO}/exchange/orders/close/’+s[‘orderID’], headers=headers, data = payload)responseJson = json.loads(response._content)orderID 60e8fc89116db05a7fdb857b1629139458123bbb67a60d23c7838 open qty 0.0311
{'userID': '60e8fc89116db05a7fdb857b', 'orderID': '60e8fc89116db05a7fdb857b1629139458123bbb67a60d23c7838_CL', 'orderType': 'market', 'buyingCurrency': 'ETH', 'sellingCurrency': 'USD', 'margin': 'true', 'buyingQty': 0.0311, 'timeInForce': 4, 'boughtQty': 0.0311, 'soldQty': 100.204, 'creationTime': 1629139525626, 'seqNumber': 5042414933, 'firstFillTime': 1629139525627, 'lastFillTime': 1629139525627, 'fills': [{'seqNumber': 5042414932, 'timestamp': 1629139525627, 'qty': 0.0311, 'price': 3221.993569131833, 'side': 'buy'}], 'completionTime': 1629139525627, 'takerQty': 0.0311}
You will see all of this activity reflected in your CoinMetro dashboard.
- 100
- 7
- Account
- ALGO
- All
- api
- article
- Assets
- Authentication
- authorization
- BEST
- binance
- Bit
- Bitcoin
- Bitfinex
- Bitstamp
- bittrex
- bnb
- BTC
- buy
- charges
- code
- Coin
- coinbase
- commission
- Creating
- Credentials
- crypto
- Crypto.com
- Currency
- Customer Support
- Customers
- dashboard
- data
- Demand
- DID
- digits
- ETH
- ETHUSD
- etoro
- EU
- EV
- exchange
- Exchanges
- experiment
- Fees
- Finally
- First
- function
- Gemini
- GM
- good
- Group
- hacking
- here
- HitBTC
- hold
- How
- How To
- hr
- HTTPS
- ia
- interest
- IP
- IP Address
- IT
- Kraken
- language
- LINK
- List
- Long
- Making
- margin trading
- Market
- medium
- NY
- offer
- open
- order
- orders
- poloniex
- price
- Reality
- Referral
- response
- REST
- rig
- Robinhood
- sell
- sentiment
- set
- Short
- Simple
- So
- start
- Strategy
- support
- Target
- Telegram
- time
- token
- trade
- trades
- Trading
- trading crypto
- transaction
- us
- USD
- users
- utility
- Utility Token
- value
- Verification
- volume
- VPN
- W
- Wallet
- Work
- writing
- X
- year