class EtherDeltaMarketMakerChart: """Tool to generate a chart displaying the EtherDelta market maker keeper trades.""" def __init__(self, args: list): parser = argparse.ArgumentParser(prog='etherdelta-market-maker-chart') parser.add_argument("--rpc-host", help="JSON-RPC host (default: `localhost')", default="localhost", type=str) parser.add_argument("--rpc-port", help="JSON-RPC port (default: `8545')", default=8545, type=int) parser.add_argument("--rpc-timeout", help="JSON-RPC timeout (in seconds, default: 60)", type=int, default=60) parser.add_argument("--etherdelta-address", help="Ethereum address of the EtherDelta contract", required=True, type=str) parser.add_argument("--sai-address", help="Ethereum address of the SAI token", required=True, type=str) parser.add_argument("--eth-address", help="Ethereum address of the ETH token", required=True, type=str) parser.add_argument( "--market-maker-address", help="Ethereum account of the market maker to analyze", required=True, type=str) parser.add_argument( "--gdax-price", help= "GDAX product (ETH-USD, BTC-USD) to use as the price history source", required=True, type=str) parser.add_argument("--past-blocks", help="Number of past blocks to analyze", required=True, type=int) parser.add_argument("-o", "--output", help="Name of the filename to save to chart to." " Will get displayed on-screen if empty", required=False, type=str) self.arguments = parser.parse_args(args) self.web3 = Web3( HTTPProvider( endpoint_uri= f"http://{self.arguments.rpc_host}:{self.arguments.rpc_port}", request_kwargs={'timeout': self.arguments.rpc_timeout})) self.infura = Web3( HTTPProvider(endpoint_uri=f"https://mainnet.infura.io/", request_kwargs={'timeout': 120})) self.sai_address = Address(self.arguments.sai_address) self.eth_address = Address(self.arguments.eth_address) self.market_maker_address = Address( self.arguments.market_maker_address) self.etherdelta = EtherDelta(web3=self.web3, address=Address( self.arguments.etherdelta_address)) initialize_charting(self.arguments.output) initialize_logging() def main(self): start_timestamp = get_block_timestamp( self.infura, self.web3.eth.blockNumber - self.arguments.past_blocks) end_timestamp = int(time.time()) events = self.etherdelta.past_trade( self.arguments.past_blocks, {'get': self.market_maker_address.address}) trades = etherdelta_trades(self.infura, self.market_maker_address, self.sai_address, self.eth_address, events) prices = get_gdax_prices(self.arguments.gdax_price, start_timestamp, end_timestamp) draw_chart(start_timestamp, end_timestamp, prices, [], 180, [], trades, [], self.arguments.output)
class EtherDeltaMarketMakerTrades: """Tool to list historical trades for the EtherDelta market maker keeper.""" def __init__(self, args: list): parser = argparse.ArgumentParser(prog='etherdelta-market-maker-trades') parser.add_argument("--rpc-host", help="JSON-RPC host (default: `localhost')", default="localhost", type=str) parser.add_argument("--rpc-port", help="JSON-RPC port (default: `8545')", default=8545, type=int) parser.add_argument("--rpc-timeout", help="JSON-RPC timeout (in seconds, default: 60)", type=int, default=60) parser.add_argument("--etherdelta-address", help="Ethereum address of the EtherDelta contract", required=True, type=str) parser.add_argument("--sai-address", help="Ethereum address of the SAI token", required=True, type=str) parser.add_argument("--eth-address", help="Ethereum address of the ETH token", required=True, type=str) parser.add_argument( "--market-maker-address", help="Ethereum account of the market maker to analyze", required=True, type=str) parser.add_argument("--past-blocks", help="Number of past blocks to analyze", required=True, type=int) parser.add_argument("-o", "--output", help="File to save the table or the JSON to", required=False, type=str) parser_mode = parser.add_mutually_exclusive_group(required=True) parser_mode.add_argument('--text', help="List trades as a text table", dest='text', action='store_true') parser_mode.add_argument('--json', help="List trades as a JSON document", dest='json', action='store_true') self.arguments = parser.parse_args(args) self.web3 = Web3( HTTPProvider( endpoint_uri= f"http://{self.arguments.rpc_host}:{self.arguments.rpc_port}", request_kwargs={'timeout': self.arguments.rpc_timeout})) self.infura = Web3( HTTPProvider(endpoint_uri=f"https://mainnet.infura.io/", request_kwargs={'timeout': 120})) self.sai_address = Address(self.arguments.sai_address) self.eth_address = Address(self.arguments.eth_address) self.market_maker_address = Address( self.arguments.market_maker_address) self.etherdelta = EtherDelta(web3=self.web3, address=Address( self.arguments.etherdelta_address)) logging.basicConfig( format='%(asctime)-15s %(levelname)-8s %(message)s', level=logging.INFO) logging.getLogger("filelock").setLevel(logging.WARNING) def sell_token(self): return "ETH" def buy_token(self): return "DAI" def main(self): past_trades = self.etherdelta.past_trade( self.arguments.past_blocks, {'get': self.market_maker_address.address}) trades = etherdelta_trades(self.infura, self.market_maker_address, self.sai_address, self.eth_address, past_trades) trades = sort_trades(trades) if self.arguments.text: text_trades(self.buy_token(), self.sell_token(), trades, self.arguments.output, include_taker=True) if self.arguments.json: json_trades(trades, self.arguments.output, include_taker=True)
class EtherDeltaMarketMakerChart: """Tool to analyze the EtherDelta Market Maker keeper performance.""" def __init__(self, args: list): parser = argparse.ArgumentParser(prog='etherdelta-market-maker-chart') parser.add_argument("--rpc-host", help="JSON-RPC host (default: `localhost')", default="localhost", type=str) parser.add_argument("--rpc-port", help="JSON-RPC port (default: `8545')", default=8545, type=int) parser.add_argument("--etherdelta-address", help="Ethereum address of the EtherDelta contract", required=True, type=str) parser.add_argument("--sai-address", help="Ethereum address of the SAI token", required=True, type=str) parser.add_argument("--eth-address", help="Ethereum address of the ETH token", required=True, type=str) parser.add_argument( "--market-maker-address", help="Ethereum account of the market maker to analyze", required=True, type=str) parser.add_argument("--past-blocks", help="Number of past blocks to analyze", required=True, type=int) parser.add_argument("-o", "--output", help="Name of the filename to save to chart to." " Will get displayed on-screen if empty", required=False, type=str) self.arguments = parser.parse_args(args) self.web3 = Web3( HTTPProvider( endpoint_uri= f"http://{self.arguments.rpc_host}:{self.arguments.rpc_port}", request_kwargs={'timeout': 120})) self.infura = Web3( HTTPProvider(endpoint_uri=f"https://mainnet.infura.io/", request_kwargs={'timeout': 120})) self.sai_address = Address(self.arguments.sai_address) self.eth_address = Address(self.arguments.eth_address) self.market_maker_address = Address( self.arguments.market_maker_address) self.etherdelta = EtherDelta(web3=self.web3, address=Address( self.arguments.etherdelta_address)) if self.arguments.output: import matplotlib matplotlib.use('Agg') def main(self): past_trade = self.etherdelta.past_trade(self.arguments.past_blocks) def sell_trades() -> List[Trade]: regular = map( lambda log_take: Trade( self.get_event_timestamp(log_take), log_take.give_amount / log_take.take_amount, log_take.give_amount, False, True), filter( lambda log_trade: log_trade.maker == self. market_maker_address and log_trade.buy_token == self. sai_address and log_trade.pay_token == self.eth_address, past_trade)) return list(regular) def buy_trades() -> List[Trade]: regular = map( lambda log_take: Trade( self.get_event_timestamp(log_take), log_take.take_amount / log_take.give_amount, log_take.take_amount, True, False), filter( lambda log_trade: log_trade.maker == self. market_maker_address and log_trade.buy_token == self. eth_address and log_trade.pay_token == self.sai_address, past_trade)) return list(regular) start_timestamp = self.get_event_timestamp(past_trade[0]) end_timestamp = int(time.time()) prices = get_gdax_prices(start_timestamp, end_timestamp) trades = sell_trades() + buy_trades() self.draw(prices, trades) def get_event_timestamp(self, event): return self.infura.eth.getBlock(event.raw['blockHash']).timestamp def convert_timestamp(self, timestamp): from matplotlib.dates import date2num return date2num(datetime.datetime.fromtimestamp(timestamp)) def to_size(self, trade: Trade): return amount_in_sai_to_size(trade.value_in_sai) def draw(self, prices: List[Price], trades: List[Trade]): import matplotlib.dates as md import matplotlib.pyplot as plt plt.subplots_adjust(bottom=0.2) plt.xticks(rotation=25) ax = plt.gca() ax.xaxis.set_major_formatter(md.DateFormatter('%Y-%m-%d %H:%M:%S')) timestamps = list( map(self.convert_timestamp, map(lambda price: price.timestamp, prices))) market_prices = list(map(lambda price: price.market_price, prices)) plt.plot_date(timestamps, market_prices, 'r-', zorder=1) sell_trades = list(filter(lambda trade: trade.is_sell, trades)) sell_x = list( map(self.convert_timestamp, map(lambda trade: trade.timestamp, sell_trades))) sell_y = list(map(lambda trade: trade.price, sell_trades)) sell_s = list(map(self.to_size, sell_trades)) plt.scatter(x=sell_x, y=sell_y, s=sell_s, c='blue', zorder=2) buy_trades = list(filter(lambda trade: trade.is_buy, trades)) buy_x = list( map(self.convert_timestamp, map(lambda trade: trade.timestamp, buy_trades))) buy_y = list(map(lambda trade: trade.price, buy_trades)) buy_s = list(map(self.to_size, buy_trades)) plt.scatter(x=buy_x, y=buy_y, s=buy_s, c='green', zorder=2) if self.arguments.output: plt.savefig(fname=self.arguments.output, dpi=300, bbox_inches='tight', pad_inches=0) else: plt.show()
class EtherDeltaMarketMakerPnl: """Tool to calculate profitability for the EtherDelta market maker keeper.""" def __init__(self, args: list): parser = argparse.ArgumentParser(prog='etherdelta-market-maker-pnl') parser.add_argument("--rpc-host", help="JSON-RPC host (default: `localhost')", default="localhost", type=str) parser.add_argument("--rpc-port", help="JSON-RPC port (default: `8545')", default=8545, type=int) parser.add_argument("--rpc-timeout", help="JSON-RPC timeout (in seconds, default: 60)", type=int, default=60) parser.add_argument("--etherdelta-address", help="Ethereum address of the EtherDelta contract", required=True, type=str) parser.add_argument("--sai-address", help="Ethereum address of the SAI token", required=True, type=str) parser.add_argument("--eth-address", help="Ethereum address of the ETH token", required=True, type=str) parser.add_argument( "--market-maker-address", help="Ethereum account of the market maker to analyze", required=True, type=str) parser.add_argument( "--gdax-price", help= "GDAX product (ETH-USD, BTC-USD) to use as the price history source", type=str) parser.add_argument( "--price-feed", help="Price endpoint to use as the price history source", type=str) parser.add_argument("--price-history-file", help="File to use as the price history source", type=str) parser.add_argument("--vwap-minutes", help="Rolling VWAP window size (default: 240)", type=int, default=240) parser.add_argument("--buy-token", help="Name of the buy token", required=True, type=str) parser.add_argument("--sell-token", help="Name of the sell token", required=True, type=str) parser.add_argument("--past-blocks", help="Number of past blocks to analyze", required=True, type=int) parser.add_argument("-o", "--output", help="File to save the chart or the table to", required=False, type=str) parser_mode = parser.add_mutually_exclusive_group(required=True) parser_mode.add_argument('--text', help="Show PnL as a text table", dest='text', action='store_true') parser_mode.add_argument('--chart', help="Show PnL on a cumulative graph", dest='chart', action='store_true') self.arguments = parser.parse_args(args) self.web3 = Web3( HTTPProvider( endpoint_uri= f"http://{self.arguments.rpc_host}:{self.arguments.rpc_port}", request_kwargs={'timeout': self.arguments.rpc_timeout})) self.infura = Web3( HTTPProvider(endpoint_uri=f"https://mainnet.infura.io/", request_kwargs={'timeout': 120})) self.sai_address = Address(self.arguments.sai_address) self.eth_address = Address(self.arguments.eth_address) self.market_maker_address = Address( self.arguments.market_maker_address) self.etherdelta = EtherDelta(web3=self.web3, address=Address( self.arguments.etherdelta_address)) if self.arguments.chart and self.arguments.output: import matplotlib matplotlib.use('Agg') logging.basicConfig( format='%(asctime)-15s %(levelname)-8s %(message)s', level=logging.INFO) logging.getLogger("filelock").setLevel(logging.WARNING) def main(self): start_timestamp = get_block_timestamp( self.infura, self.web3.eth.blockNumber - self.arguments.past_blocks) end_timestamp = int(time.time()) events = self.etherdelta.past_trade( self.arguments.past_blocks, {'get': self.market_maker_address.address}) trades = etherdelta_trades(self.infura, self.market_maker_address, self.sai_address, self.eth_address, events) trades = sort_trades_for_pnl(trades) prices = get_prices(self.arguments.gdax_price, self.arguments.price_feed, self.arguments.price_history_file, start_timestamp, end_timestamp) vwaps = get_approx_vwaps(prices, self.arguments.vwap_minutes) vwaps_start = prices[0].timestamp if self.arguments.text: pnl_text(trades, vwaps, vwaps_start, self.arguments.buy_token, self.arguments.sell_token, self.arguments.vwap_minutes, self.arguments.output) if self.arguments.chart: pnl_chart(start_timestamp, end_timestamp, prices, trades, vwaps, vwaps_start, self.arguments.buy_token, self.arguments.sell_token, self.arguments.output)