Skip to content

Commit

Permalink
Run _black_ code formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
maxme committed Apr 10, 2019
1 parent 1337930 commit 83fac40
Show file tree
Hide file tree
Showing 48 changed files with 633 additions and 398 deletions.
46 changes: 26 additions & 20 deletions arbitrage/arbitrage.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ def exec_command(self, args):
def list_markets(self):
markets = []
for filename in glob.glob(os.path.join(public_markets.__path__[0], "*.py")):
module_name = os.path.basename(filename).replace('.py', '')
if not module_name.startswith('_'):
module_name = os.path.basename(filename).replace(".py", "")
if not module_name.startswith("_"):
module = __import__("arbitrage.public_markets." + module_name)
test = eval('module.public_markets.' + module_name)
test = eval("module.public_markets." + module_name)
for name, obj in inspect.getmembers(test):
if inspect.isclass(obj) and 'Market' in (j.__name__ for j in obj.mro()[1:]):
if not obj.__module__.split('.')[-1].startswith('_'):
if inspect.isclass(obj) and "Market" in (j.__name__ for j in obj.mro()[1:]):
if not obj.__module__.split(".")[-1].startswith("_"):
markets.append(obj.__name__)
markets.sort()
print("\n".join(markets))
Expand All @@ -53,9 +53,10 @@ def get_balance(self, args):
pmarkets = args.markets.split(",")
pmarketsi = []
for pmarket in pmarkets:
exec('import arbitrage.private_markets.' + pmarket.lower())
market = eval('arbitrage.private_markets.' + pmarket.lower()
+ '.Private' + pmarket + '()')
exec("import arbitrage.private_markets." + pmarket.lower())
market = eval(
"arbitrage.private_markets." + pmarket.lower() + ".Private" + pmarket + "()"
)
pmarketsi.append(market)
for market in pmarketsi:
print(market)
Expand All @@ -73,28 +74,33 @@ def init_logger(self, args):
level = logging.VERBOSE
if args.debug:
level = logging.DEBUG
logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s',
level=level)
logging.basicConfig(format="%(asctime)s [%(levelname)s] %(message)s", level=level)

def main(self):
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--debug", help="debug verbose mode",
action="store_true")
parser.add_argument("-v", "--verbose", help="info verbose mode",
action="store_true")
parser.add_argument("-o", "--observers", type=str,
help="observers, example: -oLogger,Emailer")
parser.add_argument("-m", "--markets", type=str,
help="markets, example: -m BitstampEUR,KrakenEUR")
parser.add_argument("command", nargs='*', default="watch",
help='verb: "watch|replay-history|get-balance|list-public-markets"')
parser.add_argument("-d", "--debug", help="debug verbose mode", action="store_true")
parser.add_argument("-v", "--verbose", help="info verbose mode", action="store_true")
parser.add_argument(
"-o", "--observers", type=str, help="observers, example: -oLogger,Emailer"
)
parser.add_argument(
"-m", "--markets", type=str, help="markets, example: -m BitstampEUR,KrakenEUR"
)
parser.add_argument(
"command",
nargs="*",
default="watch",
help='verb: "watch|replay-history|get-balance|list-public-markets"',
)
args = parser.parse_args()
self.init_logger(args)
self.exec_command(args)


def main():
cli = ArbitrerCLI()
cli.main()


if __name__ == "__main__":
main()
113 changes: 64 additions & 49 deletions arbitrage/arbitrer.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,34 @@ def init_markets(self, markets):
self.market_names = markets
for market_name in markets:
try:
exec('import arbitrage.public_markets.' + market_name.lower())
market = eval('arbitrage.public_markets.' + market_name.lower() + '.' +
market_name + '()')
exec("import arbitrage.public_markets." + market_name.lower())
market = eval(
"arbitrage.public_markets." + market_name.lower() + "." + market_name + "()"
)
self.markets.append(market)
except (ImportError, AttributeError) as e:
print("%s market name is invalid: Ignored (you should check your config file)" % (market_name))
print(
"%s market name is invalid: Ignored (you should check your config file)"
% (market_name)
)

def init_observers(self, _observers):
self.observer_names = _observers
for observer_name in _observers:
try:
exec('import arbitrage.observers.' + observer_name.lower())
observer = eval('arbitrage.observers.' + observer_name.lower() + '.' +
observer_name + '()')
exec("import arbitrage.observers." + observer_name.lower())
observer = eval(
"arbitrage.observers." + observer_name.lower() + "." + observer_name + "()"
)
self.observers.append(observer)
except (ImportError, AttributeError) as e:
print("%s observer name is invalid: Ignored (you should check your config file)" % (observer_name))
print(
"%s observer name is invalid: Ignored (you should check your config file)"
% (observer_name)
)

def get_profit_for(self, mi, mj, kask, kbid):
if self.depths[kask]["asks"][mi]["price"] \
>= self.depths[kbid]["bids"][mj]["price"]:
if self.depths[kask]["asks"][mi]["price"] >= self.depths[kbid]["bids"][mj]["price"]:
return 0, 0, 0, 0

max_amount_buy = 0
Expand All @@ -58,49 +65,43 @@ def get_profit_for(self, mi, mj, kask, kbid):
w_buyprice = 0
for i in range(mi + 1):
price = self.depths[kask]["asks"][i]["price"]
amount = min(max_amount, buy_total + self.depths[
kask]["asks"][i]["amount"]) - buy_total
amount = min(max_amount, buy_total + self.depths[kask]["asks"][i]["amount"]) - buy_total
if amount <= 0:
break
buy_total += amount
if w_buyprice == 0:
w_buyprice = price
else:
w_buyprice = (w_buyprice * (
buy_total - amount) + price * amount) / buy_total
w_buyprice = (w_buyprice * (buy_total - amount) + price * amount) / buy_total

sell_total = 0
w_sellprice = 0
for j in range(mj + 1):
price = self.depths[kbid]["bids"][j]["price"]
amount = min(max_amount, sell_total + self.depths[
kbid]["bids"][j]["amount"]) - sell_total
amount = (
min(max_amount, sell_total + self.depths[kbid]["bids"][j]["amount"]) - sell_total
)
if amount < 0:
break
sell_total += amount
if w_sellprice == 0 or sell_total == 0:
w_sellprice = price
else:
w_sellprice = (w_sellprice * (
sell_total - amount) + price * amount) / sell_total
w_sellprice = (w_sellprice * (sell_total - amount) + price * amount) / sell_total

profit = sell_total * w_sellprice - buy_total * w_buyprice
return profit, sell_total, w_buyprice, w_sellprice

def get_max_depth(self, kask, kbid):
i = 0
if len(self.depths[kbid]["bids"]) != 0 and \
len(self.depths[kask]["asks"]) != 0:
while self.depths[kask]["asks"][i]["price"] \
< self.depths[kbid]["bids"][0]["price"]:
if len(self.depths[kbid]["bids"]) != 0 and len(self.depths[kask]["asks"]) != 0:
while self.depths[kask]["asks"][i]["price"] < self.depths[kbid]["bids"][0]["price"]:
if i >= len(self.depths[kask]["asks"]) - 1:
break
i += 1
j = 0
if len(self.depths[kask]["asks"]) != 0 and \
len(self.depths[kbid]["bids"]) != 0:
while self.depths[kask]["asks"][0]["price"] \
< self.depths[kbid]["bids"][j]["price"]:
if len(self.depths[kask]["asks"]) != 0 and len(self.depths[kbid]["bids"]) != 0:
while self.depths[kask]["asks"][0]["price"] < self.depths[kbid]["bids"][j]["price"]:
if j >= len(self.depths[kbid]["bids"]) - 1:
break
j += 1
Expand All @@ -114,30 +115,41 @@ def arbitrage_depth_opportunity(self, kask, kbid):
best_volume = 0
for i in range(maxi + 1):
for j in range(maxj + 1):
profit, volume, w_buyprice, w_sellprice = self.get_profit_for(
i, j, kask, kbid)
profit, volume, w_buyprice, w_sellprice = self.get_profit_for(i, j, kask, kbid)
if profit >= 0 and profit >= best_profit:
best_profit = profit
best_volume = volume
best_i, best_j = (i, j)
best_w_buyprice, best_w_sellprice = (
w_buyprice, w_sellprice)
return best_profit, best_volume, \
self.depths[kask]["asks"][best_i]["price"], \
self.depths[kbid]["bids"][best_j]["price"], \
best_w_buyprice, best_w_sellprice
best_w_buyprice, best_w_sellprice = (w_buyprice, w_sellprice)
return (
best_profit,
best_volume,
self.depths[kask]["asks"][best_i]["price"],
self.depths[kbid]["bids"][best_j]["price"],
best_w_buyprice,
best_w_sellprice,
)

def arbitrage_opportunity(self, kask, ask, kbid, bid):
perc = (bid["price"] - ask["price"]) / bid["price"] * 100
profit, volume, buyprice, sellprice, weighted_buyprice,\
weighted_sellprice = self.arbitrage_depth_opportunity(kask, kbid)
profit, volume, buyprice, sellprice, weighted_buyprice, weighted_sellprice = self.arbitrage_depth_opportunity(
kask, kbid
)
if volume == 0 or buyprice == 0:
return
perc2 = (1 - (volume - (profit / buyprice)) / volume) * 100
for observer in self.observers:
observer.opportunity(
profit, volume, buyprice, kask, sellprice, kbid,
perc2, weighted_buyprice, weighted_sellprice)
profit,
volume,
buyprice,
kask,
sellprice,
kbid,
perc2,
weighted_buyprice,
weighted_sellprice,
)

def __get_market_depth(self, market, depths):
depths[market.name] = market.get_depth()
Expand All @@ -146,24 +158,23 @@ def update_depths(self):
depths = {}
futures = []
for market in self.markets:
futures.append(self.threadpool.submit(self.__get_market_depth,
market, depths))
futures.append(self.threadpool.submit(self.__get_market_depth, market, depths))
wait(futures, timeout=20)
return depths

def tickers(self):
for market in self.markets:
logging.verbose("ticker: " + market.name + " - " + str(
market.get_ticker()))
logging.verbose("ticker: " + market.name + " - " + str(market.get_ticker()))

def replay_history(self, directory):
import os
import json
import pprint

files = os.listdir(directory)
files.sort()
for f in files:
depths = json.load(open(directory + '/' + f, 'r'))
depths = json.load(open(directory + "/" + f, "r"))
self.depths = {}
for market in self.market_names:
if market in depths:
Expand All @@ -180,12 +191,16 @@ def tick(self):
continue
market1 = self.depths[kmarket1]
market2 = self.depths[kmarket2]
if market1["asks"] and market2["bids"] \
and len(market1["asks"]) > 0 and len(market2["bids"]) > 0:
if float(market1["asks"][0]['price']) \
< float(market2["bids"][0]['price']):
self.arbitrage_opportunity(kmarket1, market1["asks"][0],
kmarket2, market2["bids"][0])
if (
market1["asks"]
and market2["bids"]
and len(market1["asks"]) > 0
and len(market2["bids"]) > 0
):
if float(market1["asks"][0]["price"]) < float(market2["bids"][0]["price"]):
self.arbitrage_opportunity(
kmarket1, market1["asks"][0], kmarket2, market2["bids"][0]
)

for observer in self.observers:
observer.end_opportunity_finder()
Expand Down
12 changes: 6 additions & 6 deletions arbitrage/config.py-example
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ markets = [
"KrakenEUR",
"KrakenUSD",
"OKCoinCNY",
"PaymiumEUR"
"PaymiumEUR",
]

# observers if any
Expand Down Expand Up @@ -43,11 +43,11 @@ profit_thresh = 1 # in EUR
perc_thresh = 2 # in %

#### Emailer Observer Config
smtp_host = 'FIXME'
smtp_login = 'FIXME'
smtp_passwd = 'FIXME'
smtp_from = 'FIXME'
smtp_to = 'FIXME'
smtp_host = "FIXME"
smtp_login = "FIXME"
smtp_passwd = "FIXME"
smtp_from = "FIXME"
smtp_to = "FIXME"

#### XMPP Observer
xmpp_jid = "[email protected]"
Expand Down
20 changes: 16 additions & 4 deletions arbitrage/observers/detailedlogger.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,19 @@


class DetailedLogger(Observer):
def opportunity(self, profit, volume, buyprice, kask, sellprice, kbid, perc,
weighted_buyprice, weighted_sellprice):
logging.info("profit: %f USD with volume: %f BTC - buy at %.4f (%s) sell at %.4f (%s) ~%.2f%%" \
% (profit, volume, buyprice, kask, sellprice, kbid, perc))
def opportunity(
self,
profit,
volume,
buyprice,
kask,
sellprice,
kbid,
perc,
weighted_buyprice,
weighted_sellprice,
):
logging.info(
"profit: %f USD with volume: %f BTC - buy at %.4f (%s) sell at %.4f (%s) ~%.2f%%"
% (profit, volume, buyprice, kask, sellprice, kbid, perc)
)
32 changes: 27 additions & 5 deletions arbitrage/observers/emailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,45 @@
def send_email(subject, message):
_to = config.smtp_to
_from = config.smtp_from
mime_message = """From: Python Arbitrage Script <%(_from)s>
mime_message = (
"""From: Python Arbitrage Script <%(_from)s>
To: <%(_to)s>
Subject: %(subject)s
%(message)s
""" % locals()
"""
% locals()
)
try:
smtpObj = smtplib.SMTP(config.smtp_host)
smtpObj.sendmail(_from, [_to], mime_message)
except smtplib.SMTPException:
logging.warn("Unable to send email")


class Emailer(Observer):
def opportunity(self, profit, volume, buyprice, kask, sellprice, kbid, perc,
weighted_buyprice, weighted_sellprice):
def opportunity(
self,
profit,
volume,
buyprice,
kask,
sellprice,
kbid,
perc,
weighted_buyprice,
weighted_sellprice,
):
if profit > config.profit_thresh and perc > config.perc_thresh:
message = """profit: %f USD with volume: %f BTC
buy at %.4f (%s) sell at %.4f (%s) ~%.2f%%
""" % (profit, volume, buyprice, kask, sellprice, kbid, perc)
""" % (
profit,
volume,
buyprice,
kask,
sellprice,
kbid,
perc,
)
send_email("Arbitrage Bot", message)
Loading

0 comments on commit 83fac40

Please sign in to comment.