You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
totrader/trade.py

223 lines
8.0 KiB

#!/usr/bin/env python
import logging
from os import getenv
from argparse import ArgumentParser
from datetime import datetime
from decimal import Decimal
from random import uniform
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'
)
class Trader(TradeOgre):
satoshi = .00000001
base_currency = 'BTC'
trade_currency = 'WOW'
trade_pair = f'{base_currency}-{trade_currency}'
trade_amount = 250
def get_market_data(self):
logging.info(f'[MARKET] 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()
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'[MARKET] Stored market data as ID {t.id}')
return t
def store_balance(self, currency):
logging.info(f'[BALANCE] Storing balance for currency {currency}')
res = self.get_balance(currency)
logging.debug(res)
b = Balance(
currency=currency,
total=res['balance'],
available=res['available']
)
b.save()
logging.info(f'[BALANCE] Stored market data as ID {b.id}')
return b
def store_balances(self):
for cur in self.base_currency, self.trade_currency:
self.store_balance(cur)
sleep(3)
def get_active_orders(self):
logging.info('[ORDERS] Getting active orders in local database')
orders = Order.select().where(Order.active==True)
logging.debug(f'Found {len(orders)} in database')
return orders
def reconcile_orders(self):
logging.info('[ORDERS] Reconciling orders on TradeOgre with local database')
to_orders = self.get_orders(self.trade_pair)
for order in to_orders:
if not Order.filter(Order.uuid==order['uuid']):
o = Order(
trade_pair=order['market'],
trade_type='manual',
buy=order['type'] == 'buy',
quantity=float(order['quantity']),
price=float(order['price']),
uuid=order['uuid'],
date=datetime.utcfromtimestamp(order['date'])
)
o.save()
logging.info(f'[ORDERS] Saved order {order["uuid"]} to the database')
def update_orders(self):
logging.info('[ORDERS] Updating orders in local database against TradeOgre')
for order in self.get_active_orders():
logging.info(f'Checking order {order.uuid}')
o = self.get_order(order.uuid)
logging.info(f'Found order: {o}')
if o['success'] is False:
order.active = False
order.save()
logging.info(f'Order {order.uuid} no longer active on TradeOgre. Setting inactive.')
sleep(5)
def start_market_maker(self):
logging.info('[MARKET MAKER] 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('[MARKET MAKER] Too many active orders in place. Skipping.')
return False
if latest.spread_sats > 4:
bid_amount = uniform(self.trade_amount, self.trade_amount + 30)
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'[MARKET MAKER] 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=self.trade_pair,
trade_type=trade_type,
buy=True,
quantity=bid_amount,
price=bid_price,
uuid=buy['uuid']
)
o.save()
logging.info(f'[MARKET MAKER] Stored buy order as ID {o.id}')
sleep(3)
logging.info(f'[MARKET MAKER] 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.info(f'[MARKET MAKER] Stored sell order as ID {o.id}')
else:
logging.info(f'[MARKET MAKER] 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('-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()
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:
t.reconcile_orders()
t.update_orders()
exit()
if args.balances:
t.store_balances()
exit()
while True:
try:
t.store_market_data()
except Exception as e:
logging.info('[ERROR] Unable to store market data!', e)
# update orders every 5 minutes
if orders_counter == 5:
try:
t.update_orders()
logging.info('[ORDERS] Resetting orders counter')
orders_counter = 0
except Exception as e:
logging.info('[ERROR] Unable to update orders!', e)
# update balances every 6 minutes
if balances_counter == 6:
try:
t.store_balances()
logging.info('[BALANCE] Resetting balances counter')
balances_counter = 0
except Exception as e:
logging.info('[ERROR] Unable to update balances!', e)
# start market makers every 2 minutes
if market_maker_counter == 2:
try:
t.start_market_maker()
logging.info('[MARKET MAKER] Resetting market maker counter')
market_maker_counter = 0
except Exception as e:
logging.info('[ERROR] Unable to start market maker!', e)
orders_counter += 1
balances_counter += 1
market_maker_counter += 1
# sleep 1 minute
sleep(60)