Advertisement
genBTC

Mt. Gox API 2/1/0

Mar 23rd, 2013
4,112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.28 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 json_ascii
  32. import urllib
  33. import urllib2
  34. import urlparse
  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 Client:
  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 = ""
  62.         self.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=0,GZIP=True,GET=False):
  92.         while True:
  93.             self.throttle()
  94.             try:
  95.                 nonce =  str(int(time.time()*1000))
  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.urlencode(params)
  104.                 ahmac = base64.b64encode(str(hmac.new(base64.b64decode(self.secret),post_data,hashlib.sha512).digest()))
  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          #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()))
  114.                
  115.                 # Create header for auth-requiring operations
  116.                 header = {
  117.                     "User-Agent": 'genBTC-bot',
  118.                     "Rest-Key": self.key,
  119.                     "Rest-Sign": ahmac
  120.                     }
  121.                 # Create the request
  122.                 if GET:
  123.                     req = urllib2.Request(url)
  124.                 else:
  125.                     req = urllib2.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 = urllib2.urlopen(req)
  132.                 else:
  133.                     resp = urllib2.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=json_ascii.decode_dict)
  142.                         if "error" in data:
  143.                             if data["error"] == "Not logged in.":
  144.                                 print UserError(data["error"])
  145.                             else:
  146.                                 print ServerError(data["error"])
  147.                     except ValueError as e:
  148.                         print "JSON Error: %s. Most likely BLANK Data." % e
  149.                         resp.seek(0)
  150.                         print resp.read()
  151.                         continue
  152.                 else:
  153.                     data = resp.read()
  154.                 return data
  155.             #Try to catch a number of possible errors.
  156.             #Since this is used for debugging, logging.debug() should really be used instead
  157.             except urllib2.HTTPError as e:
  158.                 #HTTP Error ie: 500/502/503 etc
  159.                 print 'HTTP Error %s: %s' % (e.code, e.msg)
  160.                 print "URL: %s" % (e.filename)
  161.                 if e.fp:
  162.                     datastring = e.fp.read()
  163.                     if "error" in datastring:
  164.                         if "<!DOCTYPE HTML>" in datastring:
  165.                             print "Error: Cloudflare - Website Currently Unavailable."
  166.                         elif "Order not found" in datastring:
  167.                             return json.loads(datastring)
  168.                         else:
  169.                             print "Error: %s" % datastring                            
  170.             except urllib2.URLError as e:
  171.                 print "URL Error:", e
  172.             except ssl.SSLError as e:
  173.                 print "SSL Error: %s." % e  #Read error timeout. (Removed timeout variable)
  174.             except Exception as e:
  175.                 print "General Error: %s" % e
  176.             else:
  177.             #print this before going back up to the While Loop and running this entire function over again
  178.                 print "Retrying Connection...."
  179.  
  180.  
  181.     def request(self, path, params,JSON=True,API_VERSION=0,GZIP=True,GET=False):
  182.         return self.perform(path, params,JSON,API_VERSION,GZIP,GET)
  183.  
  184.     #public api
  185.     def get_bid_history(self,OID):
  186.         params = {"type":'bid',"order":OID}
  187.         return self.request('generic/order/result',params,API_VERSION=1)
  188.    
  189.     def get_ask_history(self,OID):
  190.         params = {"type":'ask',"order":OID}
  191.         return self.request('generic/order/result',params,API_VERSION=1)
  192.  
  193.     def get_bid_tids(self,OID):
  194.         #used to link an OID from an API order to a list of TIDs reported in the account history log
  195.         try:
  196.             history = self.get_bid_history(OID)
  197.         except:
  198.             #OID not found, return an empty list
  199.             return []
  200.         else:
  201.             trade_ids = []
  202.             if history['result'] == 'success':
  203.                 for trade in history['return']['trades']:
  204.                     trade_ids.append(trade['trade_id'])
  205.                     #return the list of trade ids
  206.                     return trade_ids
  207.             else:
  208.                 return []
  209.  
  210.     def get_ask_tids(self,OID):
  211.         #used to link an OID from an API order to a list of TIDs reported in the account history log
  212.         try:
  213.             history = self.get_ask_history(OID)
  214.         except:
  215.             #OID not found, return an empty list
  216.             return []
  217.         else:
  218.             trade_ids = []
  219.             if history['result'] == 'success':
  220.                 for trade in history['return']['trades']:
  221.                     trade_ids.append(trade['trade_id'])
  222.                     #return the list of trade ids
  223.                     return trade_ids
  224.             else:
  225.                 return []
  226.  
  227.     def lag(self):
  228.         return self.request('generic/order/lag',None,API_VERSION=1,GET=True)["return"]
  229.     def get_history_btc(self):
  230.         return self.request('history_' + PRODUCT + '.csv',None,JSON=False)
  231.     def get_history_usd(self):
  232.         return self.request('history_' + CURRENCY + '.csv',None,JSON=False)
  233.     def get_info(self):
  234.         return self.request('generic/info',None,API_VERSION=1)["return"]
  235.     def get_ticker2(self):
  236.         return self.request(PAIR + "/money/ticker",None,API_VERSION=2,GET=True)["data"]
  237.     def get_ticker(self):
  238.         return self.request("ticker.php",None,GET=True)["ticker"]
  239.     def get_depth(self):
  240.         return self.request("data/getDepth.php", {"Currency":CURRENCY})
  241.     def get_fulldepth(self):
  242.         return self.request(PAIR + "/money/depth/full",None,API_VERSION=2,GET=True)
  243.     def get_trades(self):
  244.         return self.request("data/getTrades.php",None,GET=True)
  245.     def get_balance(self):
  246.         info = self.get_info()["Wallets"]
  247.         balance = { "usds":info[CURRENCY]["Balance"]["value"], "btcs":info[PRODUCT]["Balance"]["value"] }
  248.         return balance
  249.     def entire_trade_history(self):
  250.         return self.request(PAIR + "/money/trades/fetch",None,API_VERSION=2,GET=True)
  251.  
  252.     def get_spread(self):
  253.         depth = self.get_depth()
  254.         lowask = depth["asks"][0][0]
  255.         highbid = depth["bids"][-1][0]
  256.         spread = lowask - highbid
  257.         return spread
  258.  
  259.     def get_orders(self):
  260.         self.orders = self.request("getOrders.php",None)
  261.         return self.orders
  262.        
  263.     def last_order(self):
  264.         try:
  265.             orders = self.get_orders()['orders']
  266.             max_date = 0
  267.             last_order = orders[0]
  268.             for o in orders:
  269.                 if o['date'] > last_order['date']:
  270.                     last_order = o
  271.                 return last_order
  272.         except:
  273.             print 'no orders found'
  274.             return
  275.    
  276.     def order_new(self, typ, amount, price=None, protection=True):
  277.         if amount < D('0.01'):
  278.             print "Minimum amount is 0.01 %s" % PRODUCT
  279.             return None
  280.         if protection == True:
  281.             if amount > D('100.0'):
  282.                 yesno = prompt("You are about to {0} >100 {1}.".format(typ,PRODUCT),True)
  283.                 if not(yesno):
  284.                     return None
  285.         amount_int = int(D(amount) * (1/self.bPrec))
  286.         params = {"type":str(typ),
  287.                 "amount_int":amount_int
  288.                 }
  289.         if price:
  290.             price_int = int(D(price) * (1/self.cPrec))
  291.             params["price_int"] = price_int
  292.         response = self.request(PAIR + "/money/order/add", params, API_VERSION=2)
  293.         if response["result"] == "success":
  294.             return response
  295.         else:
  296.             return None
  297.  
  298.     def cancel_one(self,oid):
  299.         params = {"oid":str(oid)}
  300.         result = self.request(PAIR + "/money/order/cancel", params, API_VERSION=2)
  301.         if result["result"] == "success":
  302.             print 'OID: %s Successfully Cancelled!' % (oid)
  303.         else:
  304.             print "Order not found!!"
  305.         return self.orders
  306.  
  307.     def cancel_all(self):
  308.         orders = self.get_orders()
  309.         for order in orders['orders']:
  310.             typ = order['type']
  311.             ordertype="Sell" if typ == 1 else "Buy"
  312.             oid = order['oid']
  313.             params = {"oid":str(oid)}
  314.             result = self.request(PAIR + "/money/order/cancel", params, API_VERSION=2)
  315.             print '%s OID: %s Successfully Cancelled!' % (ordertype,oid)
  316.         if orders['orders']:
  317.             print "All Orders have been Cancelled!!!!!"
  318.             self.orders = result
  319.         else:
  320.             print "No Orders found!!"
  321.         return self.orders
  322.  
  323. #EXPERIMENTAL API
  324.  
  325. #(barely useful in testing)
  326. #puts in a "bid/ask"(typ) order of the specified amount and tells you the total as if it were making a market order
  327.     def order_quote(self,typ,amount,price=""):
  328.         params = {"type":str(typ),
  329.                 "amount":amount
  330.                 }
  331.         if price:
  332.             #price = int(D(price) * (1/self.cPrec))
  333.             params["price"] = price
  334.         result = self.request(PAIR + "/money/order/quote", params, API_VERSION=2)
  335.         if result["result"] == "success":
  336.             print 'The result was ' % (result)
  337.             return result["data"]
  338.         else:
  339.             print "Error!! %s" % result["result"]        
  340.  
  341. #tested, not 100%, hence the traceback
  342.     def bitcoin_address(self,desc=""):
  343.         #gets a bitcoin address linked to your account
  344.         #a new description creates a new address
  345.         try:
  346.             if desc:
  347.                 params = {"description":str(desc)}
  348.             else:
  349.                 params = None
  350.             response = self.request("generic/private/bitcoin/address",params,API_VERSION=1)
  351.             if "error" in response:
  352.                 print "Error!! %s" % response["error"]
  353.             elif "success" in response:
  354.                 print response["return"]["addr"]
  355.         except Exception as e:
  356.             traceback.print_exc()            
  357.  
  358. #tested, not 100%, hence the traceback
  359.     def bitcoin_withdraw(self,address,amount_int,fee_int="",no_instant=False,green=False):
  360.     #string, int, (int, bool, bool)are optional
  361.         try:
  362.             params = {"address":str(address),
  363.                     "amount_int":int(amount_int),
  364.                     "fee_int":int(fee_int),
  365.                     "no_instant":no_instant,
  366.                     "green":green
  367.                     }
  368.             response = self.request("generic/private/bitcoin/send_simple",params,API_VERSION=1)
  369.             if "error" in response:
  370.                 print "Error!! %s" % response["error"]
  371.             elif "success" in response:
  372.                 print response
  373.         except Exception as e:
  374.             traceback.print_exc()
  375.  
  376. #not sure if this one is still allowed
  377.     def bitcoin_withdraw_api0(self,address,amount,fee):
  378.     #string, int, (int, bool, bool)are optional
  379.         try:
  380.             params = {"group1":"BTC",
  381.                     "btca":str(address),
  382.                     "amount":int(amount),
  383.                     "fee":int(fee)#,
  384.                     #"no_instant":no_instant,
  385.                     #"green":green
  386.                     }
  387.             response = self.request("withdraw.php",params,API_VERSION=0)
  388.             print response
  389.             if "error" in response:
  390.                 print "Error!! %s" % response["error"]
  391.             else:
  392.                 print response['status']
  393.         except Exception as e:
  394.             traceback.print_exc()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement