Skip to content

Commit

Permalink
[ExchangeBot] Now does what it is supposed to be doing
Browse files Browse the repository at this point in the history
  • Loading branch information
xeroc committed Jan 23, 2016
1 parent ebf1990 commit e0e26df
Show file tree
Hide file tree
Showing 7 changed files with 337 additions and 81 deletions.
26 changes: 20 additions & 6 deletions scripts/exchange-bots/bot/bot.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
from grapheneapi.graphenewsprotocol import GrapheneWebsocketProtocol
from grapheneexchange import GrapheneExchange
import time


class BotProtocol(GrapheneWebsocketProtocol):
pass


class Bot():

def __init__(self, config, **kwargs):
botProtocol = BotProtocol
[setattr(botProtocol, key, config.__dict__[key]) for key in config.__dict__.keys()]

self.config = config
self.dex = GrapheneExchange(config, safe_mode=True)
self.dex = GrapheneExchange(botProtocol, safe_mode=config.safe_mode)

# Initialize all bots
self.bots = {}
for name in config.bots:
self.bots[name] = config.bots[name]["bot"](config=self.config,
name=name,
dex=self.dex)
for index, name in enumerate(config.bots, 1):
botClass = config.bots[name]["bot"]
self.bots[name] = botClass(config=config, name=name,
dex=self.dex, index=index)
self.bots[name].init()

def wait_block(self):
time.sleep(6)

def execute(self):
for name in self.bots:
self.bots[name].cancel_mine()
if self.bots[name].cancel_this_markets() and self.config.safe_mode:
self.wait_block()
self.bots[name].tick()
self.bots[name].store()
85 changes: 59 additions & 26 deletions scripts/exchange-bots/bot/strategies/basestrategy.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from grapheneexchange import GrapheneExchange
import json
import os


class BaseStrategy():

def __init__(self, *args, **kwargs):
self.state = None
self.state = {"orders" : []}

for arg in args :
if isinstance(arg, GrapheneExchange):
Expand All @@ -16,9 +17,9 @@ def __init__(self, *args, **kwargs):
if "name" not in kwargs:
raise ValueError("Missing parameter 'name'!")
self.filename = "data_%s.json" % self.name

self.settings = self.config.bots[self.name]
self.orders = []

self.restore()

def init(self) :
print("Initializing %s" % self.name)
Expand All @@ -27,30 +28,42 @@ def tick(self) :
pass

def cancel_all(self) :
orders = self.dex.returnOpenOrders()
for m in orders:
onceCanceled = False
curOrders = self.dex.returnOpenOrdersIds()
for m in curOrders:
for order in orders[m]:
self.dex.cancel(order["orderNumber"])
try :
self.dex.cancel(order["orderNumber"])
onceCanceled = True
except:
print("An error has occured when trying to cancel order %s!" % order["orderNumber"])
return onceCanceled

def cancel_mine(self) :
myOrders = []
for i, d in enumerate(self.orders):
o = {}
o["for_sale"] = d["amount_to_sell"]
myOrders.append(o)

curOrders = self.dex.returnOpenOrdersIds()
state = self.getState()
onceCanceled = False
for o in state["orders"]:
for m in curOrders:
if o in curOrders[m] :
try :
self.dex.cancel(o)
onceCanceled = True
except:
print("An error has occured when trying to cancel order %s!" % o["orderNumber"])
return onceCanceled

def cancel_this_markets(self) :
orders = self.dex.returnOpenOrders()
for m in orders:
onceCanceled = False
for m in self.settings["markets"]:
for order in orders[m]:
for stored_order in myOrders:
print("==========")
print(stored_order["for_sale"])
print(order["amount_to_sell"])
# #self.dex.cancel(order["orderNumber"])

def save_orders(self, orders):
for o in orders["operations"] :
self.orders.append(o[1])
try :
self.dex.cancel(order["orderNumber"])
onceCanceled = True
except:
print("An error has occured when trying to cancel order %s!" % order["orderNumber"])
return onceCanceled

def place(self) :
pass
Expand All @@ -62,11 +75,31 @@ def setState(self, state):
self.state = state

def store(self):
state = self.state()
state = self.getState()

orders = []
curOrders = self.dex.returnOpenOrdersIds()
for m in curOrders :
for cur in curOrders[m] :
if cur not in state["orders"] :
orders.append(cur)

state["orders"] = orders
with open(self.filename, 'w') as fp:
json.dump(state, fp)

def restore(self):
with open(self.filename, 'r') as fp:
state = json.load(fp)
self.setState(state)
if os.path.isfile(self.filename) :
with open(self.filename, 'r') as fp:
state = json.load(fp)
self.setState(state)

def sell(self, market, price, amount):
quote, base = market.split(self.config.market_separator)
print(" - Selling %f %s for %s @%f %s/%s" % (amount, quote, base, price, quote, base))
self.dex.sell(market, price, amount)

def buy(self, market, price, amount):
quote, base = market.split(self.config.market_separator)
print(" - Buying %f %s with %s @%f %s/%s" % (amount, base, quote, price, quote, base))
self.dex.buy(market, price, amount)
127 changes: 113 additions & 14 deletions scripts/exchange-bots/bot/strategies/bridgemaker.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from .basestrategy import BaseStrategy
import math
from numpy import linspace

"""
"""
Expand All @@ -9,16 +11,55 @@ class BridgeMaker(BaseStrategy):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def tick(self) :
self.cancel_mine()
self.place()

def place(self) :
print("Placing Orders:")
buy_price = 1 - self.settings["spread_percentage"] / 200
sell_price = 1 + self.settings["spread_percentage"] / 200

#: Amount of Funds available for trading (per asset)
balances = self.dex.returnBalances()
asset_ids = []
amounts = {}
for market in self.settings["markets"] :
quote, base = market.split(self.config.market_separator)
asset_ids.append(base)
asset_ids.append(quote)
assets_unique = list(set(asset_ids))
for a in assets_unique:
if a in balances :
amounts[a] = balances[a] * self.settings["volume_percentage"] / 100 / asset_ids.count(a)

for m in self.settings["markets"]:
quote, base = m.split(self.config.market_separator)
if quote in amounts :
self.sell(m, sell_price, amounts[quote])
if base in amounts :
self.buy(m, buy_price, amounts[base] * buy_price)


class BridgeMakerEqual(BaseStrategy):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def tick(self) :
self.cancel_mine()
self.place()

def place(self) :
print("Placing Orders")
print("Placing Orders:")
buy_price = 1 - self.settings["spread_percentage"] / 200
sell_price = 1 + self.settings["spread_percentage"] / 200

#: Amount of Funds available for trading (per asset)
balances = self.dex.returnBalances()
asset_ids = []
amounts = {}
for market in self.config.watch_markets :
for market in self.settings["markets"] :
quote, base = market.split(self.config.market_separator)
asset_ids.append(base)
asset_ids.append(quote)
Expand All @@ -27,18 +68,76 @@ def place(self) :
if a in balances :
amounts[a] = balances[a] * self.settings["volume_percentage"] / 100 / asset_ids.count(a)

for m in self.settings["markets"]:
quote, base = m.split(self.config.market_separator)
if quote in amounts :
self.sell(m, sell_price, min([amounts[quote], amounts[base] * buy_price]))
if base in amounts :
self.buy(m, buy_price, min([amounts[quote], amounts[base] * buy_price]))


class BridgeMakerRamp(BaseStrategy):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def tick(self) :
self.cancel_mine()
self.place()

def place(self) :
print("Placing Orders:")
orders = []
for m in self.config.watch_markets:
#: Amount of Funds available for trading (per asset)
if "ramp_mode" not in self.settings:
mode = "linear"
else :
mode = self.settings["ramp_mode"]

balances = self.dex.returnBalances()
asset_ids = []
amounts = {}
for market in self.settings["markets"]:
quote, base = market.split(self.config.market_separator)
asset_ids.append(base)
asset_ids.append(quote)
assets_unique = list(set(asset_ids))
for a in assets_unique:
if a in balances :
amounts[a] = balances[a] * self.settings["volume_percentage"] / 100 / asset_ids.count(a)

for m in self.settings["markets"]:
settlement_price = 1.0
quote, base = m.split(self.config.market_separator)
if quote in amounts :
print(" - Selling %f %s for %s @%f" % (amounts[quote], quote, base, sell_price))
tx = self.dex.sell(m, sell_price, amounts[quote])
self.add_order(tx)
elif base in amounts :
print(" - Buying %f %s with %s @%f" % (amounts[base], base, quote, buy_price))
tx = self.dex.buy(m, buy_price, amounts[base] * buy_price)
self.add_order(tx)
else:
continue
self.update_orders()
price_start = settlement_price * (1 + self.settings["spread_percentage"] / 200.0)
price_end = settlement_price * (1 + self.settings["ramp_price_percentage"] / 100.0)
amount = min([amounts[quote], amounts[base] * (price_start) / 2.0])
number_orders = math.floor((self.settings["ramp_price_percentage"] / 100.0 - self.settings["spread_percentage"] / 200.0) / (self.settings["ramp_step_percentage"] / 100.0))
if mode == "linear" :
for price in linspace(price_start, price_end, number_orders) :
self.sell(m, price, amount / number_orders)
elif mode == "exponential" :
k = linspace(1 / number_orders, 1, number_orders)
k = [v / sum(k) for v in k]
order_amounts = [v * amount for v in k]
for i, price in enumerate(linspace(price_start, price_end, number_orders)):
self.sell(m, price, order_amounts[i])
else :
raise Exception("ramp_mode '%s' not known" % mode)

if base in amounts :
price_start = settlement_price * (1 - self.settings["spread_percentage"] / 200.0)
price_end = settlement_price * (1 - self.settings["ramp_price_percentage"] / 100.0)
amount = min([amounts[quote], amounts[base] * (price_start) / 2.0])
number_orders = math.floor((self.settings["ramp_price_percentage"] / 100.0 - self.settings["spread_percentage"] / 200.0) / (self.settings["ramp_step_percentage"] / 100.0))
if mode == "linear" :
for price in linspace(price_start, price_end, number_orders) :
self.buy(m, price, amount / number_orders)
elif mode == "exponential" :
k = linspace(1 / number_orders, 1, number_orders)
k = [v / sum(k) for v in k]
order_amounts = [v * amount for v in k]
for i, price in enumerate(linspace(price_start, price_end, number_orders)):
self.buy(m, price, order_amounts[i])
else :
raise Exception("ramp_mode '%s' not known" % mode)
Loading

0 comments on commit e0e26df

Please sign in to comment.