From bfc3e6b0826864c8d71635ac657fdf5a7a2569dc Mon Sep 17 00:00:00 2001 From: lza_menace Date: Mon, 7 Sep 2020 02:30:25 -0700 Subject: [PATCH] move TradeOgre to its own module, setup all actions in the loop with counters, new Trader class --- trade.py | 280 ++++++++++++++++++++++++++++----------------------- tradeogre.py | 45 +++++++++ 2 files changed, 197 insertions(+), 128 deletions(-) create mode 100644 tradeogre.py diff --git a/trade.py b/trade.py index dc12240..765e99e 100755 --- a/trade.py +++ b/trade.py @@ -1,164 +1,188 @@ #!/usr/bin/env python -from argparse import ArgumentParser +import logging from os import getenv -from dotenv import load_dotenv -from requests import get as requests_get -from requests import post as requests_post -from requests.auth import HTTPBasicAuth +from argparse import ArgumentParser from decimal import Decimal from random import uniform -from pprint import pprint from time import sleep from db import Ticker, Balance, Order +from tradeogre import TradeOgre +logging.basicConfig( + level=getenv('LOGLEVEL', 'INFO'), + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) -satoshi = .00000001 +class Trader(TradeOgre): -class TradeOgre(object): - def __init__(self): - load_dotenv('.env') - self.base = 'https://tradeogre.com/api/v1' - self.auth = HTTPBasicAuth( - getenv('TO_USER'), - getenv('TO_PASS') + satoshi = .00000001 + base_currency = 'BTC' + trade_currency = 'WOW' + trade_pair = f'{base_currency}-{trade_currency}' + + def get_market_data(self): + logging.info(f'Getting market data for trade pair {self.trade_pair}') + res = self.get_trade_pair(self.trade_pair) + spread_btc = Decimal(res['ask']) - Decimal(res['bid']) + spread_sats = float(spread_btc / Decimal(self.satoshi)) + spread_perc = (spread_btc / Decimal(res['ask'])) * 100 + res['spread_btc'] = spread_btc + res['spread_sats'] = spread_sats + res['spread_perc'] = spread_perc + logging.debug(res) + return res + + def store_market_data(self): + res = self.get_market_data() + logging.info(f'Storing market data for trade pair {self.trade_pair}') + t = Ticker( + trade_pair=self.trade_pair, + initial_price=res['initialprice'], + current_price=res['price'], + high_price=res['high'], + low_price=res['low'], + volume=res['volume'], + bid=res['bid'], + ask=res['ask'], + spread_btc=res['spread_btc'], + spread_sats=res['spread_sats'], + spread_perc=res['spread_perc'] ) + t.save() + logging.info(f'Stored market data as ID {t.id}') + return t - def req(self, route, method='get', data={}): - url = self.base + route - if method == 'get': - r = requests_get(url, auth=self.auth) - else: - r = requests_post(url, auth=self.auth, data=data) - return r.json() - - def get_trade_pair(self, pair): - route = f'/ticker/{pair}' - return self.req(route) - - def get_balance(self, currency): - route = '/account/balance' - data = {'currency': currency} - return self.req(route, 'post', data) - - def get_balances(self): - route = '/account/balances' - return self.req(route) - - def submit_order(self, type, pair, quantity, price): - route = f'/order/{type}' - data = {'market': pair, 'quantity': quantity, 'price': price} - return self.req(route, 'post', data) - - def get_order(self, uuid): - route = f'/account/order/{uuid}' - return self.req(route) - - -def get_metrics(): - # define vars - to = TradeOgre() - base = 'BTC' - currency = 'WOW' - trade_pair = f'{base}-{currency}' - - # get market data - tp_res = to.get_trade_pair(trade_pair) - print(tp_res) - spreat_btc = Decimal(tp_res['ask']) - Decimal(tp_res['bid']) - spread_sats = float(spreat_btc / Decimal(.00000001)) - spread_perc = (spreat_btc / Decimal(tp_res['ask'])) * 100 - - # store market data in db - t = Ticker( - trade_pair=trade_pair, - initial_price=tp_res['initialprice'], - current_price=tp_res['price'], - high_price=tp_res['high'], - low_price=tp_res['low'], - volume=tp_res['volume'], - bid=tp_res['bid'], - ask=tp_res['ask'], - spread_btc=spreat_btc, - spread_sats=spread_sats, - spread_perc=spread_perc - ) - t.save() - - # get balances and store in db - for c in base, currency: - gb_res = to.get_balance(c) - print(gb_res) + def store_balance(self, currency): + logging.info(f'Storing balance for currency {currency}') + res = self.get_balance(currency) + logging.debug(res) b = Balance( - currency=c, - total=gb_res['balance'], - available=gb_res['available'] + currency=currency, + total=res['balance'], + available=res['available'] ) b.save() + logging.info(f'Stored market data as ID {b.id}') + return b -def put_market_maker(): - to = TradeOgre() - latest_ticker = Ticker.select().order_by(Ticker.date.desc()).get() - if latest_ticker.spread_sats > 4: - bid_amount = uniform(80, 90) - ask_amount = uniform(80, 90) - to_bid = latest_ticker.bid + satoshi - to_ask = latest_ticker.ask - satoshi - buy = to.submit_order('buy', 'BTC-WOW', bid_amount, '{:.8f}'.format(to_bid)) - print(buy) - if buy['success']: - o = Order( - trade_pair='BTC-WOW', - trade_type='market_maker', - buy=True, - quantity=bid_amount, - price=to_bid, - uuid=buy['uuid'] - ) - o.save() - + def store_balances(self): + for cur in self.base_currency, self.trade_currency: + self.store_balance(cur) sleep(3) - sell = to.submit_order('sell', 'BTC-WOW', ask_amount, '{:.8f}'.format(to_ask)) - print(sell) - if sell['success']: + + def get_active_orders(self): + logging.info('Getting active orders in local database') + orders = Order.select().where(Order.active==True) + logging.debug(f'Found {len(orders)} in database') + return orders + + def update_orders(self): + logging.info('Updating orders in local database against TradeOgre') + for order in self.get_active_orders(): + logging.debug(f'Checking order {order.uuid}') + o = self.get_order(order.uuid) + logging.debug(f'Found order: {o}') + if o['success'] is False: + order.active = False + order.save() + logging.debug(f'Order {order.uuid} no longer active on TradeOgre. Setting inactive.') + sleep(5) + + def start_market_maker(self): + logging.info('Starting market maker') + latest = Ticker.select().order_by(Ticker.date.desc()).get() + trade_type = 'market_maker' + + if len(self.get_active_orders()) > 5: + logging.info('Too many active orders in place. Skipping.') + return False + + if latest.spread_sats > 4: + bid_amount = uniform(100, 130) + ask_amount = uniform(bid_amount - 6, bid_amount + 6) + bid_price = '{:.8f}'.format(latest.bid + self.satoshi) + ask_price = '{:.8f}'.format(latest.ask - self.satoshi) + logging.info(f'Submitting buy order for {bid_amount} at {bid_price} {self.trade_pair}') + buy = self.submit_order('buy', self.trade_pair, bid_amount, bid_price) + logging.debug(buy) + if buy['success']: o = Order( - trade_pair='BTC-WOW', - trade_type='market_maker', - buy=False, - quantity=ask_amount, - price=to_ask, - uuid=sell['uuid'] + trade_pair=self.trade_pair, + trade_type=trade_type, + buy=True, + quantity=bid_amount, + price=bid_price, + uuid=buy['uuid'] ) o.save() + logging.debug(f'Stored buy order as ID {o.id}') + sleep(3) -def check_orders(): - to = TradeOgre() - orders = Order.select().where(Order.active==True) - for order in orders: - print(order.uuid) - o = to.get_order(order.uuid) - print(o) - if o['success'] is False: - order.active = False - order.save() - sleep(5) + logging.info(f'Submitting sell order for {ask_amount} at {ask_price} {self.trade_pair}') + sell = self.submit_order('sell', self.trade_pair, ask_amount, ask_price) + logging.debug(sell) + if sell['success']: + o = Order( + trade_pair=self.trade_pair, + trade_type=trade_type, + buy=False, + quantity=ask_amount, + price=ask_price, + uuid=sell['uuid'] + ) + o.save() + logging.debug(f'Stored sell order as ID {o.id}') + else: + logging.info(f'Not enough bid-ask spread ({latest.spread_sats} sats). Skipping market maker.') if __name__ == '__main__': parser = ArgumentParser(description='Helpful TradeOgre trading script') - parser.add_argument('-t', '--trade', action='store_true', help='Put in buy/sell orders') + parser.add_argument('-m', '--market-maker', action='store_true', help='Put in buy/sell orders') + parser.add_argument('-b', '--balances', action='store_true', help='Update coin balances of both base and currency') parser.add_argument('-u', '--update-orders', action='store_true', help='Update status of orders') args = parser.parse_args() - if args.trade: - put_market_maker() + t = Trader() + orders_counter = 0 + balances_counter = 0 + market_maker_counter = 0 + + if args.market_maker: + t.start_market_maker() exit() if args.update_orders: - check_orders() + t.update_orders() + exit() + + if args.balances: + t.store_balances() exit() while True: - get_metrics() + t.store_market_data() + + # update orders every 5 minutes + if orders_counter == 5: + t.update_orders() + orders_counter = 0 + + # update balances every 2 minutes + if balances_counter == 2: + t.store_balances() + balances_counter = 0 + + # start market makers every 3 minutes + if market_maker_counter == 3: + t.start_market_maker() + market_maker_counter = 0 + + orders_counter += 1 + balances_counter += 1 + market_maker_counter += 1 + + # sleep 1 minute sleep(60) diff --git a/tradeogre.py b/tradeogre.py new file mode 100644 index 0000000..17639f2 --- /dev/null +++ b/tradeogre.py @@ -0,0 +1,45 @@ +from os import getenv +from dotenv import load_dotenv +from requests import get as requests_get +from requests import post as requests_post +from requests.auth import HTTPBasicAuth + + +class TradeOgre(object): + def __init__(self): + load_dotenv('.env') + self.base = 'https://tradeogre.com/api/v1' + self.auth = HTTPBasicAuth( + getenv('TO_USER'), + getenv('TO_PASS') + ) + + def req(self, route, method='get', data={}): + url = self.base + route + if method == 'get': + r = requests_get(url, auth=self.auth) + else: + r = requests_post(url, auth=self.auth, data=data) + return r.json() + + def get_trade_pair(self, pair): + route = f'/ticker/{pair}' + return self.req(route) + + def get_balance(self, currency): + route = '/account/balance' + data = {'currency': currency} + return self.req(route, 'post', data) + + def get_balances(self): + route = '/account/balances' + return self.req(route) + + def submit_order(self, type, pair, quantity, price): + route = f'/order/{type}' + data = {'market': pair, 'quantity': quantity, 'price': price} + return self.req(route, 'post', data) + + def get_order(self, uuid): + route = f'/account/order/{uuid}' + return self.req(route)