Advertisement
Guest User

MtGox API v2 Python

a guest
Apr 28th, 2013
479
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.60 KB | None | 0 0
  1. """
  2. MtGoxHMAC v0.31
  3.  
  4. Copyright 2011 Brian Monkaba
  5. Modified 4/4/2013 by genBTC
  6. Git Repo: https://github.com/genbtc/trader.python/
  7. This file *was* part of ga-bitbot. It was modified heavily and is now part of genBTC's program.
  8.  
  9.    ga-bitbot is free software: you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation, either version 3 of the License, or
  12.    (at your option) any later version.
  13.  
  14.    ga-bitbot is distributed in the hope that it will be useful,
  15.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License
  20.    along with ga-bitbot.  If not, see <http://www.gnu.org/licenses/>.
  21. """
  22.  
  23. from contextlib import closing
  24. from Crypto.Cipher import AES
  25. import getpass
  26. import base64
  27. import hmac
  28. import hashlib
  29. import time
  30. import json
  31. import urllib
  32. import urllib.error
  33. import urllib.parse
  34. import urllib.request
  35. import ssl
  36. import gzip
  37. import io
  38. from decimal import Decimal as D
  39. import traceback
  40.  
  41. CURRENCY = "USD"
  42. PRODUCT = "BTC"     #maybe future litecoin implementations can work off this
  43. PAIR = PRODUCT + CURRENCY
  44.  
  45. class UserError(Exception):
  46.     def __init__(self, errmsg):
  47.         self.errmsg = errmsg
  48.     def __str__(self):
  49.         return self.errmsg
  50.  
  51. class ServerError(Exception):
  52.     def __init__(self, ret):
  53.         self.ret = ret
  54.     def __str__(self):
  55.         return "Server error: %s" % self.ret
  56.  
  57. class MtGOX():
  58.     def __init__(self):
  59.  
  60.         #replace the following with your own API key and secret, or use the encryption found at the git repo
  61.         self.key = 'My key'
  62.         self.secret = 'My Secret'
  63.        
  64.         self.buff = ""
  65.         self.timeout = 3
  66.         self.__url_parts = "https://data.mtgox.com/api/"
  67.         self.clock_last = time.time()
  68.         self.clock = time.time()
  69.         self.query_count = 0
  70.         self.query_limit_per_time_slice = 9
  71.         self.query_time_slice = 6
  72.        
  73.         self.cPrec = D('0.00001')
  74.         self.bPrec = D('0.00000001')
  75.  
  76.         self.orders = []
  77.         self.fulldepth = []
  78.  
  79.     def throttle(self):
  80.         self.clock = time.time()
  81.         tdelta = self.clock - self.clock_last
  82.         if tdelta > self.query_time_slice:
  83.             self.query_count = 0
  84.             self.clock_last = time.time()
  85.         self.query_count += 1
  86.         if self.query_count > self.query_limit_per_time_slice:
  87.             #throttle the connection
  88.             print ('### Throttled ###')
  89.             time.sleep(self.query_time_slice - tdelta)
  90.        
  91.     def perform(self, path, params,JSON=True,API_VERSION=2,GZIP=True,GET=False):
  92.         while True:
  93.             self.throttle()
  94.             try:
  95.                 nonce =  str(int(time.time()*1000)) + "000"
  96.                 if params != None:
  97.                     if isinstance(params, dict):
  98.                         params = params.items()
  99.                 else:
  100.                     params = []
  101.  
  102.                 params += [(u'nonce',nonce)]
  103.                 post_data = urllib.parse.urlencode(params)
  104.                 #ahmac = base64.b64encode(str(hmac.new(base64.b64decode(self.secret),post_data,hashlib.sha512).digest()).encode('ascii'))
  105.                
  106.                 if API_VERSION == 0:
  107.                     url = self.__url_parts + '0/' + path
  108.                 elif API_VERSION == 1:
  109.                     url = self.__url_parts + '1/' + path
  110.                 else: #assuming API_VERSION 2
  111.                     url = self.__url_parts + '2/' + path
  112.                     api2postdatatohash = (path + chr(0) + post_data).encode('utf-8')          #new way to hash for API 2, includes path + NUL
  113.                     ahmac = base64.b64encode(str(hmac.new(base64.b64decode(self.secret),api2postdatatohash,hashlib.sha512).digest()).encode('utf-8'))
  114.                
  115.                 # Create header for auth-requiring operations
  116.                 header = {
  117.                     "User-Agent": 'Arbitrater',
  118.                     "Rest-Key": self.key,
  119.                     "Rest-Sign": ahmac
  120.                     }
  121.                 # Create the request
  122.                 if GET:
  123.                     req = urllib.request.Request(url)
  124.                 else:
  125.                     req = urllib.request.Request(url, post_data, header)
  126.                 # if GZIP was set, accept gzip encoding
  127.                 if GZIP:
  128.                     req.add_header('Accept-encoding', 'gzip')
  129.                 # Send the request to the server and receive the response
  130.                 if GET:
  131.                     resp = urllib.request.urlopen(req)
  132.                 else:
  133.                     resp = urllib.request.urlopen(req, post_data)
  134.                 # Un-Gzip the response
  135.                 if resp.info().get('Content-Encoding') == 'gzip':
  136.                     buf = io.BytesIO(resp.read())
  137.                     resp = gzip.GzipFile(fileobj=buf)
  138.                 # if JSON was set, json-ify the response, or say what went wrong, otherwise return plain data
  139.                 if JSON == True:
  140.                     try:
  141.                         #data = json.load(resp,object_hook=self.decode_dict)
  142.                         data = json.loads(resp.read().decode('utf8'))
  143.                         if "error" in data:
  144.                             if data["error"] == "Not logged in.":
  145.                                 print (UserError(data["error"]))
  146.                             else:
  147.                                 print (ServerError(data["error"]))
  148.                     except ValueError as e:
  149.                         print ("JSON Error: %s. Most likely BLANK Data." % e)
  150.                         resp.seek(0)
  151.                         print (resp.read())
  152.                         continue
  153.                 else:
  154.                     data = resp.read().decode('utf8')
  155.                 return data
  156.             #Try to catch a number of possible errors.
  157.             #Since this is used for debugging, logging.debug() should really be used instead
  158.             except urllib.error.HTTPError as e:
  159.                 print ("%s." % e)
  160.                 #HTTP Error ie: 500/502/503 etc
  161.                 print ('HTTP Error %s: %s' % (e.code, e.msg))
  162.                 print ("URL: %s" % (e.filename))
  163.                 #if e.fp:
  164.                 #    datastring = e.fp.read()
  165.                 #    if "error" in datastring:
  166.                 #        if "<!DOCTYPE HTML>" in datastring:
  167.                 #            print ("Error: Cloudflare - Website Currently Unavailable.")
  168.                 #        elif "Order not found" in datastring:
  169.                 #            return json.loads(datastring)
  170.                 #        else:
  171.                 #            print ("Error: %s" % datastring)
  172.             except urllib.error.URLError as e:
  173.                 print ("URL Error:", e)
  174.             except ssl.SSLError as e:
  175.                 print ("SSL Error: %s." % e)  #Read error timeout. (Removed timeout variable)
  176.             #except Exception as e:
  177.                # print ("General Error: %s" % e)
  178.             else:
  179.             #print this before going back up to the While Loop and running this entire function over again
  180.                 print ("Retrying Connection....")
  181.  
  182.  
  183.     def request(self, path, params,JSON=True,API_VERSION=0,GZIP=True,GET=False):
  184.         return self.perform(path, params,JSON,API_VERSION,GZIP,GET)
  185.  
  186.     #public api
  187.     def get_bid_history(self,OID):
  188.         params = {"type":'bid',"order":OID}
  189.         return self.request('generic/order/result',params,API_VERSION=1)
  190.    
  191.     def get_ask_history(self,OID):
  192.         params = {"type":'ask',"order":OID}
  193.         return self.request('generic/order/result',params,API_VERSION=1)
  194.  
  195.     def get_bid_tids(self,OID):
  196.         #used to link an OID from an API order to a list of TIDs reported in the account history log
  197.         try:
  198.             history = self.get_bid_history(OID)
  199.         except:
  200.             #OID not found, return an empty list
  201.             return []
  202.         else:
  203.             trade_ids = []
  204.             if history['result'] == 'success':
  205.                 for trade in history['return']['trades']:
  206.                     trade_ids.append(trade['trade_id'])
  207.                     #return the list of trade ids
  208.                     return trade_ids
  209.             else:
  210.                 return []
  211.  
  212.     def get_ask_tids(self,OID):
  213.         #used to link an OID from an API order to a list of TIDs reported in the account history log
  214.         try:
  215.             history = self.get_ask_history(OID)
  216.         except:
  217.             #OID not found, return an empty list
  218.             return []
  219.         else:
  220.             trade_ids = []
  221.             if history['result'] == 'success':
  222.                 for trade in history['return']['trades']:
  223.                     trade_ids.append(trade['trade_id'])
  224.                     #return the list of trade ids
  225.                     return trade_ids
  226.             else:
  227.                 return []
  228.  
  229.     def lag(self):
  230.         return self.request('generic/order/lag',None,API_VERSION=1,GET=True)["return"]
  231.     def get_history_btc(self):
  232.         return self.request('history_' + PRODUCT + '.csv',None,JSON=False)
  233.     def get_history_usd(self):
  234.         return self.request('history_' + CURRENCY + '.csv',None,JSON=False)
  235.     def get_info(self):
  236.         return self.request(PAIR + "/money/bitcoin/address",None,API_VERSION=2,GET=True)["return"]
  237.     def get_ticker2(self):
  238.         return self.request(PAIR + "/money/ticker",None,API_VERSION=2,GET=True)["data"]
  239.     def get_ticker(self):
  240.         print('here')
  241.         return self.request("ticker.php",None,API_VERSION=1,GET=True)["ticker"]
  242.     def get_depth(self):
  243.         return self.request(PAIR + "/money/depth/fetch", None,API_VERSION=2,GET=True)
  244.        
  245.     def get_fulldepth(self):
  246.         return self.request(PAIR + "/money/depth/full",None,API_VERSION=2,GET=True)
  247.     def get_trades(self):
  248.         return self.request("data/getTrades.php",None,GET=True)
  249.     def get_balance(self):
  250.         info = self.get_info()["Wallets"]
  251.         balance = { "usds":info[CURRENCY]["Balance"]["value"], "btcs":info[PRODUCT]["Balance"]["value"] }
  252.         return balance
  253.     def entire_trade_history(self):
  254.         return self.request(PAIR + "/money/trades/fetch",None,API_VERSION=2,GET=True)
  255.  
  256.     def get_spread(self):
  257.         depth = self.get_depth()
  258.         lowask = depth["asks"][0][0]
  259.         highbid = depth["bids"][-1][0]
  260.         spread = lowask - highbid
  261.         return spread
  262.  
  263.     def get_orders(self):
  264.         self.orders = self.request("getOrders.php",None)
  265.         return self.orders
  266.        
  267.     def last_order(self):
  268.         try:
  269.             orders = self.get_orders()['orders']
  270.             max_date = 0
  271.             last_order = orders[0]
  272.             for o in orders:
  273.                 if o['date'] > last_order['date']:
  274.                     last_order = o
  275.                 return last_order
  276.         except:
  277.             print ('no orders found')
  278.             return
  279.    
  280.     def order_new(self, typ, amount, price=None, protection=True):
  281.         if amount < D('0.01'):
  282.             print ("Minimum amount is 0.01 %s" % PRODUCT)
  283.             return None
  284.         if protection == True:
  285.             if amount > D('100.0'):
  286.                 yesno = prompt("You are about to {0} >100 {1}.".format(typ,PRODUCT),True)
  287.                 if not(yesno):
  288.                     return None
  289.         amount_int = int(D(amount) * (1/self.bPrec))
  290.         params = {"type":str(typ),
  291.                 "amount_int":amount_int
  292.                 }
  293.         if price:
  294.             price_int = int(D(price) * (1/self.cPrec))
  295.             params["price_int"] = price_int
  296.         response = self.request(PAIR + "/money/order/add", params, API_VERSION=2)
  297.         if response["result"] == "success":
  298.             return response
  299.         else:
  300.             return None
  301.  
  302.     def cancel_one(self,oid):
  303.         params = {"oid":str(oid)}
  304.         result = self.request(PAIR + "/money/order/cancel", params, API_VERSION=2)
  305.         if result["result"] == "success":
  306.             print ('OID: %s Successfully Cancelled!' % (oid))
  307.         else:
  308.             print ("Order not found!!")
  309.         return self.orders
  310.  
  311.     def cancel_all(self):
  312.         orders = self.get_orders()
  313.         for order in orders['orders']:
  314.             typ = order['type']
  315.             ordertype="Sell" if typ == 1 else "Buy"
  316.             oid = order['oid']
  317.             params = {"oid":str(oid)}
  318.             result = self.request(PAIR + "/money/order/cancel", params, API_VERSION=2)
  319.             print ('%s OID: %s Successfully Cancelled!' % (ordertype,oid))
  320.         if orders['orders']:
  321.             print ("All Orders have been Cancelled!!!!!")
  322.             self.orders = result
  323.         else:
  324.             print ("No Orders found!!")
  325.         return self.orders
  326.        
  327.     def decode_dict(dct):
  328.         newdict = {}
  329.         for k, v in dct.iteritems():
  330.             if isinstance(k, unicode):
  331.                 k = k.encode('utf-8')
  332.             if isinstance(v, unicode):
  333.                 v = v.encode('utf-8')
  334.             elif isinstance(v, list):
  335.                 v = _decode_list(v)
  336.             newdict[k] = v
  337.         return newdict
  338.        
  339. if __name__ == "__main__":
  340.  
  341.     import argparse
  342.     parser = argparse.ArgumentParser()
  343.     parser.add_argument("-b", "--buy", type=str, help="buy")
  344.     parser.add_argument("-s", "--sell", type=str, help="sell")
  345.     parser.add_argument("-t", "--transfer", type=str, help="transfer")
  346.     parser.add_argument("command", nargs='*', help='verb: "get-depth|get-balance"')
  347.     args = parser.parse_args()
  348.  
  349.     market = MtGOX()
  350.    
  351.     if args.sell:
  352.  
  353.         quantity, price = args.sell.split(",")
  354.         #output = market.request('sell', quantity, price)
  355.        
  356.         print(output)
  357.    
  358.     elif args.buy:
  359.  
  360.         quantity, price = args.buy.split(",")
  361.         #output = market.request('buy', quantity, price)
  362.        
  363.         print(output)
  364.  
  365.     elif args.transfer:
  366.         address, quantity = args.transfer.split(",")
  367.         #output = market.request('bitcoin_withdrawal', quantity, address)
  368.         print(output)
  369.    
  370.     elif "get-depth" in args.command:  
  371.         print(market.get_depth())
  372.        
  373.     elif "get-balance" in args.command:
  374.         print('Get-balance')
  375.         #print(market.request('balance'))
  376.        
  377.     elif "get-orders" in args.command:
  378.         print('open-orders')
  379.         #print(market.request('open_orders'))
  380.        
  381.     elif "get-btc-address" in args.command:
  382.         print(market.get_info())
  383.         #print(market._send_request(btc_address_url, params))
  384.        
  385.     elif "get-ticker" in args.command:
  386.         print(market.get_ticker2())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement