class JsonOutput(object): def __init__(self, file, logLimit, exchange=''): self.jsonOutputFile = file self.jsonOutput = {} self.clearStatusValues() self.jsonOutputLog = RingBuffer(logLimit) self.jsonOutput['exchange'] = exchange self.jsonOutput['label'] = Config.get("BOT", "label", "Lending Bot") def status(self, status, time, days_remaining_msg): self.jsonOutput["last_update"] = time + days_remaining_msg self.jsonOutput["last_status"] = status def printline(self, line): line = line.replace("\n", ' | ') self.jsonOutputLog.append(line) def writeJsonFile(self): with io.open(self.jsonOutputFile, 'w', encoding='utf-8') as f: self.jsonOutput["log"] = self.jsonOutputLog.get() f.write(json.dumps(self.jsonOutput, ensure_ascii=True, sort_keys=True)) def addSectionLog(self, section, key, value): if section not in self.jsonOutput: self.jsonOutput[section] = {} if key not in self.jsonOutput[section]: self.jsonOutput[section][key] = {} self.jsonOutput[section][key] = value def statusValue(self, coin, key, value): if coin not in self.jsonOutputCoins: self.jsonOutputCoins[coin] = {} self.jsonOutputCoins[coin][key] = str(value) def clearStatusValues(self): self.jsonOutputCoins = {} self.jsonOutput["raw_data"] = self.jsonOutputCoins self.jsonOutputCurrency = {} self.jsonOutput["outputCurrency"] = self.jsonOutputCurrency def outputCurrency(self, key, value): self.jsonOutputCurrency[key] = str(value)
class Bitfinex(ExchangeApi): def __init__(self, cfg, log): super(Bitfinex, self).__init__(cfg, log) self.cfg = cfg self.log = log self.lock = threading.RLock() self.req_per_min = 60 self.req_period = 15 # seconds self.req_per_period = int(self.req_per_min / ( 60.0 / self.req_period)) self.req_time_log = RingBuffer(self.req_per_period) self.url = 'https://api.bitfinex.com' self.key = self.cfg.get("API", "apikey", None) self.secret = self.cfg.get("API", "secret", None) self.apiVersion = 'v1' self.symbols = [] self.ticker = {} self.tickerTime = 0 self.usedCurrencies = [] self.timeout = int(self.cfg.get("BOT", "timeout", 30, 1, 180)) # Initialize usedCurrencies _ = self.return_available_account_balances("lending") @property def _nonce(self): """ Returns a nonce Used in authentication """ return str(int(round(time.time() * 1000))) @ExchangeApi.synchronized def limit_request_rate(self): now = time.time() # start checking only when request time log is full if len(self.req_time_log) == self.req_per_period: time_since_oldest_req = now - self.req_time_log[0] # check if oldest request is more than self.req_period ago if time_since_oldest_req < self.req_period: # print self.req_time_log.get() # uncomment to debug # print("Waiting {0} sec, {1} to keep api request rate".format(self.req_period - time_since_oldest_req, # threading.current_thread())) # print("Req:{0} Oldest req:{1} Diff:{2} sec".format(now, self.req_time_log[0], time_since_oldest_req)) self.req_time_log.append(now + self.req_period - time_since_oldest_req) time.sleep(self.req_period - time_since_oldest_req) return # uncomment to debug # else: # print self.req_time_log.get() # print("Not Waiting {0}".format(threading.current_thread())) # print("Req:{0} Oldest req:{1} Diff:{2} sec".format(now, self.req_time_log[0], time_since_oldest_req)) # append current request time to the log, pushing out the 60th request time before it self.req_time_log.append(now) def _sign_payload(self, payload): j = json.dumps(payload) data = base64.standard_b64encode(j.encode('utf8')) h = hmac.new(self.secret.encode('utf8'), data, hashlib.sha384) signature = h.hexdigest() return { "X-BFX-APIKEY": self.key, "X-BFX-SIGNATURE": signature, "X-BFX-PAYLOAD": data, "Connection": "close" } @ExchangeApi.synchronized def _request(self, method, request, payload=None, verify=True): now = time.time() try: # keep the 60 request per minute limit self.limit_request_rate() r = {} url = '{}{}'.format(self.url, request) if method == 'get': r = requests.get(url, timeout=self.timeout, headers={'Connection':'close'}) else: r = requests.post(url, headers=payload, verify=verify, timeout=self.timeout) if r.status_code != 200: if r.status_code == 502 or r.status_code in range(520, 527, 1): raise ApiError('API Error ' + str(r.status_code) + ': The web server reported a bad gateway or gateway timeout error.') else: raise ApiError('API Error ' + str(r.status_code) + ': ' + r.text) return r.json() except Exception as ex: ex.message = ex.message if ex.message else str(ex) ex.message = "{0} Requesting {1}".format(ex.message, self.url + request) raise ex def _post(self, command, payload=None, verify=True): payload = payload or {} payload['request'] = '/{}/{}'.format(self.apiVersion, command) payload['nonce'] = self._nonce signed_payload = self._sign_payload(payload) return self._request('post', payload['request'], signed_payload, verify) def _get(self, command): request = '/{}/{}'.format(self.apiVersion, command) return self._request('get', request) def _get_symbols(self): """ A list of symbol names. Currently "btcusd", "ltcusd", "ltcbtc", ... https://bitfinex.readme.io/v1/reference#rest-public-symbols """ if len(self.symbols) == 0: bfx_resp = self._get('symbols') all_currencies = self.cfg.get_all_currencies() for symbol in bfx_resp: base = symbol[3:].upper() curr = symbol[:3].upper() if base in ['USD', 'BTC'] and curr in all_currencies: self.symbols.append(symbol) return self.symbols def return_open_loan_offers(self): """ Returns active loan offers https://bitfinex.readme.io/v1/reference#rest-auth-offers """ bfx_resp = self._post('offers') resp = Bitfinex2Poloniex.convertOpenLoanOffers(bfx_resp) return resp def return_loan_orders(self, currency, limit=0): command = ('lendbook/' + currency + '?limit_asks=' + str(limit) + '&limit_bids=' + str(limit)) bfx_resp = self._get(command) resp = Bitfinex2Poloniex.convertLoanOrders(bfx_resp) return resp def return_active_loans(self): """ Returns own active loan offers https://bitfinex.readme.io/v1/reference#rest-auth-offers """ bfx_resp = self._post('credits') resp = Bitfinex2Poloniex.convertActiveLoans(bfx_resp) return resp def return_ticker(self): """ The ticker is a high level overview of the state of the market https://bitfinex.readme.io/v1/reference#rest-public-ticker """ t = int(time.time()) if t - self.tickerTime < 60: return self.ticker set_ticker_time = True for symbol in self._get_symbols(): base = symbol[3:].upper() curr = symbol[:3].upper() if base in ['BTC', 'USD'] and (curr == 'BTC' or curr in self.usedCurrencies): couple = (base + '_' + curr) couple_reverse = (curr + '_' + base) try: ticker = self._get('pubticker/' + symbol) if 'message' in ticker: raise ApiError("Error: {} ({})".format(ticker['message'], symbol)) self.ticker[couple] = { "last": ticker['last_price'], "lowestAsk": ticker['ask'], "highestBid": ticker['bid'], "percentChange": "", "baseVolume": str(float(ticker['volume']) * float(ticker['mid'])), "quoteVolume": ticker['volume'] } self.ticker[couple_reverse] = { "last": 1 / float(self.ticker[couple]['last']), "lowestAsk": 1 / float(self.ticker[couple]['lowestAsk']), "highestBid": 1 / float(self.ticker[couple]['highestBid']) } except Exception as ex: self.log.log_error('Error retrieving ticker for {}: {}. Continue with next currency.' .format(symbol, ex.message)) set_ticker_time = False continue if set_ticker_time and len(self.ticker) > 2: # USD_BTC and BTC_USD are always in self.tickerTime = t return self.ticker def return_available_account_balances(self, account): """ Returns own balances sorted by account https://bitfinex.readme.io/v1/reference#rest-auth-wallet-balances """ bfx_resp = self._post('balances') balances = Bitfinex2Poloniex.convertAccountBalances(bfx_resp, account) if 'lending' in balances: for curr in balances['lending']: if curr not in self.usedCurrencies: self.usedCurrencies.append(curr) return balances def cancel_loan_offer(self, currency, order_number): """ Cancels an offer https://bitfinex.readme.io/v1/reference#rest-auth-cancel-offer """ payload = { "offer_id": order_number, } bfx_resp = self._post('offer/cancel', payload) success = 0 message = '' try: if bfx_resp['id'] == order_number: success = 1 message = "Loan offer canceled ({:.4f} @ {:.4f}%).".format(float(bfx_resp['remaining_amount']), float(bfx_resp['rate']) / 365) except Exception as e: message = "Error canceling offer: ", str(e) success = 0 return {"success": success, "message": message} def create_loan_offer(self, currency, amount, duration, auto_renew, lending_rate): """ Creates a loan offer for a given currency. https://bitfinex.readme.io/v1/reference#rest-auth-new-offer """ payload = { "currency": currency, "amount": str(amount), "rate": str(round(float(lending_rate),10) * 36500), "period": int(duration), "direction": "lend" } try: bfx_resp = self._post('offer/new', payload) plx_resp = {"success": 0, "message": "Error", "orderID": 0} if bfx_resp['id']: plx_resp['orderId'] = bfx_resp['id'] plx_resp['success'] = 1 plx_resp['message'] = "Loan order placed." return plx_resp except Exception as e: msg = str(e) # "Invalid offer: incorrect amount, minimum is 50 dollar or equivalent in USD" if "Invalid offer: incorrect amount, minimum is 50" in msg: usd_min = 50 cur_min = usd_min if currency != 'USD': cur_min = usd_min / float(self.return_ticker()['USD_' + currency]['lowestAsk']) raise Exception("Error create_loan_offer: Amount must be at least " + str(cur_min) + " " + currency) else: raise e def return_balances(self): """ Returns balances of exchange wallet https://bitfinex.readme.io/v1/reference#rest-auth-wallet-balances """ balances = self.return_available_account_balances('exchange') return balances['exchange'] def transfer_balance(self, currency, amount, from_account, to_account): """ Transfers values from one account/wallet to another https://bitfinex.readme.io/v1/reference#rest-auth-transfer-between-wallets """ account_map = { 'margin': 'trading', 'lending': 'deposit', 'exchange': 'exchange' } payload = { "currency": currency, "amount": amount, "walletfrom": account_map[from_account], "walletto": account_map[to_account] } bfx_resp = self._post('transfer', payload) plx_resp = { "status": 1 if bfx_resp[0]['status'] == "success" else 0, "message": bfx_resp[0]['message'] } return plx_resp def return_lending_history(self, start, stop, limit=500): """ Retrieves balance ledger entries. Search funding payments in it and returns it as history. https://bitfinex.readme.io/v1/reference#rest-auth-balance-history """ history = [] all_currencies = self.cfg.get_all_currencies() for curr in all_currencies: payload = { "currency": curr, "since": str(start), "until": str(stop), "limit": limit, "wallet": "deposit" } bfx_resp = self._post('history', payload) for entry in bfx_resp: if 'Margin Funding Payment' in entry['description']: amount = float(entry['amount']) history.append({ "id": int(float(entry['timestamp'])), "currency": curr, "rate": "0.0", "amount": "0.0", "duration": "0.0", "interest": str(amount / 0.85), "fee": str(amount-amount / 0.85), "earned": str(amount), "open": Bitfinex2Poloniex.convertTimestamp(entry['timestamp']), "close": Bitfinex2Poloniex.convertTimestamp(entry['timestamp']) }) return history
class Poloniex(ExchangeApi): def __init__(self, cfg): self.cfg = cfg self.APIKey = self.cfg.get("API", "apikey", None) self.Secret = self.cfg.get("API", "secret", None) self.req_per_sec = 6 self.req_time_log = RingBuffer(self.req_per_sec) self.lock = threading.RLock() socket.setdefaulttimeout(int(Config.get("BOT", "timeout", 30, 1, 180))) @synchronized def limit_request_rate(self): now = time.time() # start checking only when request time log is full if len(self.req_time_log) == self.req_per_sec: time_since_oldest_req = now - self.req_time_log[0] # check if oldest request is more than 1sec ago if time_since_oldest_req < 1: # print self.req_time_log.get() # uncomment to debug # print "Waiting %s sec to keep api request rate" % str(1 - time_since_oldest_req) # print "Req: %d 6th Req: %d Diff: %f sec" %(now, self.req_time_log[0], time_since_oldest_req) self.req_time_log.append(now + 1 - time_since_oldest_req) time.sleep(1 - time_since_oldest_req) return # uncomment to debug # else: # print self.req_time_log.get() # print "Req: %d 6th Req: %d Diff: %f sec" % (now, self.req_time_log[0], time_since_oldest_req) # append current request time to the log, pushing out the 6th request time before it self.req_time_log.append(now) @synchronized def api_query(self, command, req=None): # keep the 6 request per sec limit self.limit_request_rate() if req is None: req = {} def _read_response(resp): data = json.loads(resp.read()) if 'error' in data: raise ApiError(data['error']) return data try: if command == "returnTicker" or command == "return24hVolume": ret = urllib2.urlopen( urllib2.Request('https://poloniex.com/public?command=' + command)) return _read_response(ret) elif command == "returnOrderBook": ret = urllib2.urlopen( urllib2.Request('https://poloniex.com/public?command=' + command + '¤cyPair=' + str(req['currencyPair']))) return _read_response(ret) elif command == "returnMarketTradeHistory": ret = urllib2.urlopen( urllib2.Request('https://poloniex.com/public?command=' + "returnTradeHistory" + '¤cyPair=' + str(req['currencyPair']))) return _read_response(ret) elif command == "returnLoanOrders": req_url = ('https://poloniex.com/public?command=' + "returnLoanOrders" + '¤cy=' + str(req['currency'])) if req['limit'] > 0: req_url += ('&limit=' + str(req['limit'])) ret = urllib2.urlopen(urllib2.Request(req_url)) return _read_response(ret) else: req['command'] = command req['nonce'] = int(time.time() * 1000) post_data = urllib.urlencode(req) sign = hmac.new(self.Secret, post_data, hashlib.sha512).hexdigest() headers = {'Sign': sign, 'Key': self.APIKey} ret = urllib2.urlopen( urllib2.Request('https://poloniex.com/tradingApi', post_data, headers)) json_ret = _read_response(ret) return post_process(json_ret) except urllib2.HTTPError as ex: raw_polo_response = ex.read() try: data = json.loads(raw_polo_response) polo_error_msg = data['error'] except Exception as ex: if ex.code == 502 or ex.code in range(520, 526, 1): # 502 and 520-526 Bad Gateway so response is likely HTML from Cloudflare polo_error_msg = '' else: polo_error_msg = raw_polo_response ex.message = ex.message if ex.message else str(ex) ex.message = "{0} Requesting {1}. Poloniex reports: '{2}'".format( ex.message, command, polo_error_msg) raise ex except Exception as ex: ex.message = ex.message if ex.message else str(ex) ex.message = "{0} Requesting {1}".format(ex.message, command) raise def return_ticker(self): return self.api_query("returnTicker") def return24h_volume(self): return self.api_query("return24hVolume") def return_order_book(self, currency_pair): return self.api_query("returnOrderBook", {'currencyPair': currency_pair}) def return_market_trade_history(self, currency_pair): return self.api_query("returnMarketTradeHistory", {'currencyPair': currency_pair}) def transfer_balance(self, currency, amount, from_account, to_account): return self.api_query( "transferBalance", { 'currency': currency, 'amount': amount, 'fromAccount': from_account, 'toAccount': to_account }) # Returns all of your balances. # Outputs: # {"BTC":"0.59098578","LTC":"3.31117268", ... } def return_balances(self): return self.api_query('returnBalances') def return_available_account_balances(self, account): balances = self.api_query('returnAvailableAccountBalances', {"account": account}) if isinstance( balances, list ): # silly api wrapper, empty dict returns a list, which breaks the code later. balances = {} return balances # Returns your open orders for a given market, specified by the "currencyPair" POST parameter, e.g. "BTC_XCP" # Inputs: # currencyPair The currency pair e.g. "BTC_XCP" # Outputs: # orderNumber The order number # type sell or buy # rate Price the order is selling or buying at # Amount Quantity of order # total Total value of order (price * quantity) def return_open_orders(self, currency_pair): return self.api_query('returnOpenOrders', {"currencyPair": currency_pair}) def return_open_loan_offers(self): loan_offers = self.api_query('returnOpenLoanOffers') if isinstance( loan_offers, list ): # silly api wrapper, empty dict returns a list, which breaks the code later. loan_offers = {} return loan_offers def return_active_loans(self): return self.api_query('returnActiveLoans') def return_lending_history(self, start, stop, limit=500): return self.api_query('returnLendingHistory', { 'start': start, 'end': stop, 'limit': limit }) # Returns your trade history for a given market, specified by the "currencyPair" POST parameter # Inputs: # currencyPair The currency pair e.g. "BTC_XCP" # Outputs: # date Date in the form: "2014-02-19 03:44:59" # rate Price the order is selling or buying at # amount Quantity of order # total Total value of order (price * quantity) # type sell or buy def return_trade_history(self, currency_pair): return self.api_query('returnTradeHistory', {"currencyPair": currency_pair}) # Places a buy order in a given market. Required POST parameters are "currencyPair", "rate", and "amount". # If successful, the method will return the order number. # Inputs: # currencyPair The curreny pair # rate price the order is buying at # amount Amount of coins to buy # Outputs: # orderNumber The order number def buy(self, currency_pair, rate, amount): return self.api_query('buy', { "currencyPair": currency_pair, "rate": rate, "amount": amount }) # Places a sell order in a given market. Required POST parameters are "currencyPair", "rate", and "amount". # If successful, the method will return the order number. # Inputs: # currencyPair The curreny pair # rate price the order is selling at # amount Amount of coins to sell # Outputs: # orderNumber The order number def sell(self, currency_pair, rate, amount): return self.api_query('sell', { "currencyPair": currency_pair, "rate": rate, "amount": amount }) def create_loan_offer(self, currency, amount, duration, auto_renew, lending_rate): return self.api_query( 'createLoanOffer', { "currency": currency, "amount": amount, "duration": duration, "autoRenew": auto_renew, "lendingRate": lending_rate, }) # Cancels an order you have placed in a given market. Required POST parameters are "currencyPair" and "orderNumber". # Inputs: # currencyPair The curreny pair # orderNumber The order number to cancel # Outputs: # succes 1 or 0 def cancel(self, currency_pair, order_number): return self.api_query('cancelOrder', { "currencyPair": currency_pair, "orderNumber": order_number }) def cancel_loan_offer(self, currency, order_number): return self.api_query('cancelLoanOffer', { "currency": currency, "orderNumber": order_number }) # Immediately places a withdrawal for a given currency, with no email confirmation. # In order to use this method, the withdrawal privilege must be enabled for your API key. # Required POST parameters are "currency", "amount", and "address". Sample output: {"response":"Withdrew 2398 NXT."} # Inputs: # currency The currency to withdraw # amount The amount of this coin to withdraw # address The withdrawal address # Outputs: # response Text containing message about the withdrawal def withdraw(self, currency, amount, address): return self.api_query('withdraw', { "currency": currency, "amount": amount, "address": address }) def return_loan_orders(self, currency, limit=0): return self.api_query('returnLoanOrders', { "currency": currency, "limit": limit }) # Toggles the auto renew setting for the specified orderNumber def toggle_auto_renew(self, order_number): return self.api_query('toggleAutoRenew', {"orderNumber": order_number})
class Poloniex: def __init__(self, api_key, secret): self.APIKey = api_key self.Secret = secret self.req_per_sec = 6 self.req_time_log = RingBuffer(self.req_per_sec) self.lock = threading.RLock() socket.setdefaulttimeout(30) @synchronized def limit_request_rate(self): now = time.time() # start checking only when request time log is full if len(self.req_time_log) == self.req_per_sec: time_since_oldest_req = now - self.req_time_log[0] # check if oldest request is more than 1sec ago if time_since_oldest_req < 1: # print self.req_time_log.get() # uncomment to debug # print "Waiting %s sec to keep api request rate" % str(1 - time_since_oldest_req) # print "Req: %d 6th Req: %d Diff: %f sec" %(now, self.req_time_log[0], time_since_oldest_req) self.req_time_log.append(now + 1 - time_since_oldest_req) time.sleep(1 - time_since_oldest_req) return # uncomment to debug # else: # print self.req_time_log.get() # print "Req: %d 6th Req: %d Diff: %f sec" % (now, self.req_time_log[0], time_since_oldest_req) # append current request time to the log, pushing out the 6th request time before it self.req_time_log.append(now) @synchronized def api_query(self, command, req=None): # keep the 6 request per sec limit self.limit_request_rate() if req is None: req = {} def _read_response(resp): data = json.loads(resp.read()) if 'error' in data: raise PoloniexApiError(data['error']) return data try: if command == "returnTicker" or command == "return24hVolume": ret = urllib2.urlopen(urllib2.Request('https://poloniex.com/public?command=' + command)) return _read_response(ret) elif command == "returnOrderBook": ret = urllib2.urlopen(urllib2.Request( 'https://poloniex.com/public?command=' + command + '¤cyPair=' + str(req['currencyPair']))) return _read_response(ret) elif command == "returnMarketTradeHistory": ret = urllib2.urlopen(urllib2.Request( 'https://poloniex.com/public?command=' + "returnTradeHistory" + '¤cyPair=' + str( req['currencyPair']))) return _read_response(ret) elif command == "returnLoanOrders": req_url = 'https://poloniex.com/public?command=' + "returnLoanOrders" + '¤cy=' + str(req['currency']) if req['limit'] != '': req_url += '&limit=' + str(req['limit']) ret = urllib2.urlopen(urllib2.Request(req_url)) return _read_response(ret) else: req['command'] = command req['nonce'] = int(time.time() * 1000) post_data = urllib.urlencode(req) sign = hmac.new(self.Secret, post_data, hashlib.sha512).hexdigest() headers = { 'Sign': sign, 'Key': self.APIKey } ret = urllib2.urlopen(urllib2.Request('https://poloniex.com/tradingApi', post_data, headers)) json_ret = _read_response(ret) return post_process(json_ret) except Exception as ex: ex.message = ex.message if ex.message else str(ex) ex.message = "{0} Requesting {1}".format(ex.message, command) raise def return_ticker(self): return self.api_query("returnTicker") def return24h_volume(self): return self.api_query("return24hVolume") def return_order_book(self, currency_pair): return self.api_query("returnOrderBook", {'currencyPair': currency_pair}) def return_market_trade_history(self, currency_pair): return self.api_query("returnMarketTradeHistory", {'currencyPair': currency_pair}) def transfer_balance(self, currency, amount, from_account, to_account): return self.api_query("transferBalance", {'currency': currency, 'amount': amount, 'fromAccount': from_account, 'toAccount': to_account}) # Returns all of your balances. # Outputs: # {"BTC":"0.59098578","LTC":"3.31117268", ... } def return_balances(self): return self.api_query('returnBalances') def return_available_account_balances(self, account): balances = self.api_query('returnAvailableAccountBalances', {"account": account}) if isinstance(balances, list): # silly api wrapper, empty dict returns a list, which breaks the code later. balances = {} return balances # Returns your open orders for a given market, specified by the "currencyPair" POST parameter, e.g. "BTC_XCP" # Inputs: # currencyPair The currency pair e.g. "BTC_XCP" # Outputs: # orderNumber The order number # type sell or buy # rate Price the order is selling or buying at # Amount Quantity of order # total Total value of order (price * quantity) def return_open_orders(self, currency_pair): return self.api_query('returnOpenOrders', {"currencyPair": currency_pair}) def return_open_loan_offers(self): loan_offers = self.api_query('returnOpenLoanOffers') if isinstance(loan_offers, list): # silly api wrapper, empty dict returns a list, which breaks the code later. loan_offers = {} return loan_offers def return_active_loans(self): return self.api_query('returnActiveLoans') # Returns your trade history for a given market, specified by the "currencyPair" POST parameter # Inputs: # currencyPair The currency pair e.g. "BTC_XCP" # Outputs: # date Date in the form: "2014-02-19 03:44:59" # rate Price the order is selling or buying at # amount Quantity of order # total Total value of order (price * quantity) # type sell or buy def return_trade_history(self, currency_pair): return self.api_query('returnTradeHistory', {"currencyPair": currency_pair}) # Places a buy order in a given market. Required POST parameters are "currencyPair", "rate", and "amount". # If successful, the method will return the order number. # Inputs: # currencyPair The curreny pair # rate price the order is buying at # amount Amount of coins to buy # Outputs: # orderNumber The order number def buy(self, currency_pair, rate, amount): return self.api_query('buy', {"currencyPair": currency_pair, "rate": rate, "amount": amount}) # Places a sell order in a given market. Required POST parameters are "currencyPair", "rate", and "amount". # If successful, the method will return the order number. # Inputs: # currencyPair The curreny pair # rate price the order is selling at # amount Amount of coins to sell # Outputs: # orderNumber The order number def sell(self, currency_pair, rate, amount): return self.api_query('sell', {"currencyPair": currency_pair, "rate": rate, "amount": amount}) def create_loan_offer(self, currency, amount, duration, auto_renew, lending_rate): return self.api_query('createLoanOffer', {"currency": currency, "amount": amount, "duration": duration, "autoRenew": auto_renew, "lendingRate": lending_rate, }) # Cancels an order you have placed in a given market. Required POST parameters are "currencyPair" and "orderNumber". # Inputs: # currencyPair The curreny pair # orderNumber The order number to cancel # Outputs: # succes 1 or 0 def cancel(self, currency_pair, order_number): return self.api_query('cancelOrder', {"currencyPair": currency_pair, "orderNumber": order_number}) def cancel_loan_offer(self, currency, order_number): return self.api_query('cancelLoanOffer', {"currency": currency, "orderNumber": order_number}) # Immediately places a withdrawal for a given currency, with no email confirmation. # In order to use this method, the withdrawal privilege must be enabled for your API key. # Required POST parameters are "currency", "amount", and "address". Sample output: {"response":"Withdrew 2398 NXT."} # Inputs: # currency The currency to withdraw # amount The amount of this coin to withdraw # address The withdrawal address # Outputs: # response Text containing message about the withdrawal def withdraw(self, currency, amount, address): return self.api_query('withdraw', {"currency": currency, "amount": amount, "address": address}) def return_loan_orders(self, currency, limit=''): return self.api_query('returnLoanOrders', {"currency": currency, "limit": limit}) # Toggles the auto renew setting for the specified orderNumber def toggle_auto_renew(self, order_number): return self.api_query('toggleAutoRenew', {"orderNumber": order_number})