def __init__(self, key, sec): Thread.__init__(self) self._core = MtGoxCore(key, sec) # start with a clean order book logger.info('Initialising; Swiping order book...') while True: data = self._core.orders() oids = map(lambda o: o['oid'], data['orders'] ) logger.debug(oids) if oids == []: break map(self._core.cancel, oids) logger.info('Order book is clean') self._orders = {} self._balance = convert.balance(data) self._lock = Lock() self._running = False logger.info('Initialisation done!')
import time from mtgoxcore import MtGoxCore from tradehillcore import TradehillCore from decimal import Decimal GOXFEE = Decimal("0.0053") HILFEE = Decimal("0.0054") # Referral code gox = MtGoxCore() hil = TradehillCore() while True: goxtick = gox.ticker()["ticker"] hiltick = hil.ticker()["ticker"] goxsell = Decimal(goxtick["buy"]) * (1 - GOXFEE) goxbuy = Decimal(goxtick["sell"]) / (1 - GOXFEE) hilsell = Decimal(hiltick["buy"]) * (1 - HILFEE) hilbuy = Decimal(hiltick["sell"]) / (1 - HILFEE) if hilbuy < goxsell: print time.ctime(time.time()) print " Buy on Tradehill for %.3f, sell on MtGox for %.3f --\ make %.2f%% profit!" % ( hilbuy, goxsell, 100 * (goxsell - hilbuy) / hilbuy, ) if goxbuy < hilsell: print time.ctime(time.time()) print " Buy on MtGox for %.3f, sell on Tradehill for %.3f --\ make %.2f%% profit!" % (
# logging.basicConfig( # format = '%(name)-12s: %(message)s', # ) # logging.getLogger('MtGoxCore').setLevel(logging.DEBUG) # logging.getLogger('MtGox').setLevel(logging.DEBUG) import time, convert, pynotify, logging from mtgoxcore import MtGoxCore from config import KEY, SEC from decimal import Decimal FEE = Decimal('0.0043') gox = MtGoxCore(KEY, SEC) bal = convert.balance(gox.balance()) #bal = {'btcs': Decimal(40), 'usds': Decimal(0)} while True: try: tic = convert.ticker(gox.ticker()) newbal = convert.balance(gox.balance()) last = tic['last'] buy = tic['sell'] sell = tic['buy'] usds = bal['usds'] btcs = bal['btcs'] newusds = newbal['usds'] newbtcs = newbal['btcs'] valusds = (1 - FEE) * newbtcs * last + newusds
class MtGox(Thread): def __init__(self, key, sec): Thread.__init__(self) self._core = MtGoxCore(key, sec) # start with a clean order book logger.info('Initialising; Swiping order book...') while True: data = self._core.orders() oids = map(lambda o: o['oid'], data['orders'] ) logger.debug(oids) if oids == []: break map(self._core.cancel, oids) logger.info('Order book is clean') self._orders = {} self._balance = convert.balance(data) self._lock = Lock() self._running = False logger.info('Initialisation done!') def run(self): self._running = True logger.info('Syncronisation thread started (hi mom!)') while self._running: self._sync() time.sleep(INTERVAL) logger.info('Ending syncronisation thread') def stop(self): self._running = False def _sync(self): # logger.info('Syncronising orders...') # logger.debug('Acquiring lock...') self._lock.acquire() # logger.debug('Lock acquired!') if self._orders == {}: # logger.info('Nothing to do; Syncronisation done!') # logger.debug('Releasing lock') self._lock.release() return logger.info('Syncronising orders...') def index(orders): bids = {} asks = {} for o in orders: p = o['price'] if o['type'] == 'bid': d = bids else: d = asks if not p in d: d[p] = [] d[p].append(o) return (bids, asks) def sum_amounts(xs): return sum(map(lambda x: x['amount'], xs)) def tot_amounts(xs): return sum(map(sum_amounts, xs.values())) def partition(orders): live = [] dead = [] now = time.time() for o in orders: if o['status'] != 'open': dead.append(o) elif o['ttl'] is not None and \ o['date'] + o['ttl'] < now: o['status'] = 'timed_out' dead.append(o) else: live.append(o) f = lambda x: x['date'] return (sorted(live, key = f), sorted(dead, key = f)) def callback(o, f, *args): logger.debug('Callback for %s: %s%s' % (o['oid'], f, repr(args))) try: o['callbacks'][f](o, *args) except Exception, e: logger.debug('Callback %s for order %s failed: %s' % (f, o['oid'], e)) pass cancelled = None data = self._core.orders() orders = convert.orders(data) balance = convert.balance(data) while True: logger.debug('Building indexes') logger.debug('Orderbook from MtGox: %s' % data) (oldbids, oldasks) = index(self._orders.values()) (oldbtcs, oldusds) = (self._balance['btcs'], self._balance['usds']) (newbids, newasks) = index(orders) (newbtcs, newusds) = (balance['btcs'], balance['usds']) # check for cancelation if cancelled is not None: logger.debug('Checking if %s was cancelled' % cancelled['oid']) bought = tot_amounts(oldbids) - tot_amounts(newbids) sold = tot_amounts(oldasks) - tot_amounts(newasks) delta1 = bought * (1 - BUY_FEE) - sold * (1 - SELL_FEE) if cancelled['type'] == 'bid': delta2 = (bought - cancelled['amount']) * (1 - BUY_FEE) - \ sold * (1 - SELL_FEE) d = oldbids f = self._core.buy else: delta2 = bought * (1 - BUY_FEE) - \ (sold - cancelled['amount']) * (1 - SELL_FEE) d = oldasks f = self._core.sell real_delta = newbtcs - oldbtcs logger.debug('Sold %.2f -- Bough %.2f' % (sold, bought)) logger.debug('Deltas: not cancelled %.2f -- cancelled %.2f -- real %.2f' % (delta1, delta2, real_delta)) if abs(abs(delta1) - abs(real_delta)) > abs(abs(delta2) - abs(real_delta)): # Was cancelled - prune local orders logger.debug('Order was cancelled: %s at %.2f USD' % (cancelled['oid'], cancelled['price'])) (live, dead) = partition(d[cancelled['price']]) logger.debug('Live: %s', live) logger.debug('Dead: %s', dead) dead_left = False for o in dead: if cancelled['amount'] >= o['amount']: oid = o['oid'] cancelled['amount'] -= o['amount'] o['cancelled_amount'] = o['amount'] o['amount'] = Decimal(0) if o['status'] == 'timed_out': callback(o, 'onTimeout') else: callback(o, 'onCancel') del self._orders[oid] continue if not cancelled['amount'].is_zero(): o['cancelled_amount'] += cancelled['amount'] o['amount'] -= cancelled['amount'] dead_left = True break # If the cancelled amount was too large: if not dead_left and not cancelled['amount'].is_zero(): logger.debug('Cancelled order too large; replacing...') f(cancelled['amount'], cancelled['price']) logger.debug('Done!') cancelled = None continue # rebuild indexes else: logger.debug('Order was not cancelled: %s as %.2f USD' % (cancelled['oid'], cancelled['price'])) # Was not cancelled - do nothing cancelled = None # check for progress and/or filled orders try: price = (oldusds - newusds) / (newbtcs - oldbtcs) except: price = Decimal(0) def process(old, new): logger.debug('Processing orders...') logger.debug('Old: %s', old) logger.debug('New: %s', new) to_cancel = [] for (p, os) in old.items(): logger.debug('Processing at price %.2f USD', p) oldamount = sum_amounts(os) if p in new: newamount = sum_amounts(new[p]) else: newamount = Decimal(0) amount = oldamount - newamount (live, dead) = partition(os) os = live + dead logger.debug('Bought %.2f BTC', amount) logger.debug('Orders to process: %s', os) for o in os: oid = o['oid'] if o['amount'] <= amount: # filled amount -= o['amount'] a = o['amount'] o['filled_amount'] += o['amount'] o['amount'] = Decimal(0) callback(o, 'onProgress', a, price) callback(o, 'onFilled') del self._orders[oid] continue if not amount.is_zero(): # part filled o['filled_amount'] += amount o['amount'] -= amount callback(o, 'onProgress', amount, price) if o['status'] is not 'open': # we're processing non-open orders -- cancel! logger.debug('Need to cancel at price %.2f' % p) logger.debug('Candidates for cancelation: %s', new[p]) to_cancel += new[p] break logger.debug('Processing done!') return to_cancel to_cancel = \ process(oldbids, newbids) + \ process(oldasks, newasks) # we're now up to date logger.debug('Old balance was: %s', self._balance) self._balance = balance logger.debug('New balance is: %s', self._balance) # check for orders to cancel if to_cancel == []: logger.info('Nothing to cancel; Synchronisation done!') break # pick 'invalid' orders first, then 'open', last 'pending' def key(x): s = x['status'] if s == 'invalid': return 0 elif s == 'open': return 1 elif s == 'pending': return 2 return 0 random.shuffle(to_cancel) # avoid always going for lowest bid cancelled = sorted(to_cancel, key = key)[0] # cancelled = to_cancel[random.randrange(0, len(to_cancel))] logger.debug('Cancelling order: %s at %.2f USD' % (cancelled['oid'], cancelled['price'])) data = self._core.cancel(cancelled['oid']) orders = convert.orders(data) balance = convert.balance(data) #end while logger.debug('Releasing lock') self._lock.release()
from mtgoxcore import MtGoxCore from config import KEY, SEC import time, json gox = MtGoxCore(KEY, SEC) file_raw = 'history.raw.json' file_prices = 'history.prices.pickled' try: with open(file_raw) as f: print "Reading saved trades from disk" trades = json.load(f) since = trades[-1]['tid'] print "Read %d trades from disk" % len(trades) except: since = 0 trades = [] while True: t = gox.trades(since) print "%s -- %s" % (time.ctime(t[0]['date']), time.ctime(t[-1]['date'])) trades = trades + t if len(t) < 100: break since = t[-1]['tid'] with open(file_raw, 'w') as f: print "Writing %d trades to disk" % len(trades) json.dump(trades, f)