class ZrxMarketMakerChart: """Tool to generate a chart displaying the 0x market maker keeper trades.""" def __init__(self, args: list): parser = argparse.ArgumentParser(prog='0x-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("--exchange-address", help="Ethereum address of the 0x contract", required=True, type=str) parser.add_argument("--buy-token-address", help="Ethereum address of the buy token", required=True, type=str) parser.add_argument("--buy-token-decimals", help="Number of decimals for the buy token", type=int, default=18) parser.add_argument("--sell-token-address", help="Ethereum address of the sell token", required=True, type=str) parser.add_argument("--sell-token-decimals", help="Number of decimals for the sell token", type=int, default=18) parser.add_argument("--old-sell-token-address", help="Ethereum address of the old sell token", required=False, 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("--alternative-price-feed", help="Price endpoint to use as the alternative price history source", type=str) parser.add_argument("--order-history", help="Order history endpoint from which to fetch our order history", 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.buy_token_address = Address(self.arguments.buy_token_address) self.sell_token_address = Address(self.arguments.sell_token_address) self.old_sell_token_address = Address(self.arguments.old_sell_token_address) if self.arguments.old_sell_token_address else None self.sell_token_addresses = list(filter(lambda address: address is not None, [self.sell_token_address, self.old_sell_token_address])) self.market_maker_address = Address(self.arguments.market_maker_address) self.exchange = ZrxExchange(web3=self.web3, address=Address(self.arguments.exchange_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.exchange.past_fill(self.arguments.past_blocks, {'maker': self.market_maker_address.address}) trades = zrx_trades(self.infura, self.market_maker_address, 'DAI', self.buy_token_address, self.arguments.buy_token_decimals, 'WETH', self.sell_token_addresses, self.arguments.sell_token_decimals, events, '-') prices = get_prices(self.arguments.gdax_price, self.arguments.price_feed, None, start_timestamp, end_timestamp) alternative_prices = get_prices(None, self.arguments.alternative_price_feed, None, start_timestamp, end_timestamp) order_history = get_order_history(self.arguments.order_history, start_timestamp, end_timestamp) order_history = prepare_order_history_for_charting(order_history) draw_chart(start_timestamp, end_timestamp, prices, alternative_prices, 180, order_history, trades, [], self.arguments.output)
class ZrxMarketMakerPnl: """Tool to calculate profitability for the 0x market maker keeper.""" def __init__(self, args: list): parser = argparse.ArgumentParser(prog='0x-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("--exchange-address", help="Ethereum address of the 0x contract", 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("--buy-token-address", help="Ethereum address of the buy token", required=True, type=str) parser.add_argument("--buy-token-decimals", help="Number of decimals for the buy token", type=int, default=18) parser.add_argument("--sell-token", help="Name of the sell token", required=True, type=str) parser.add_argument("--sell-token-address", help="Ethereum address of the sell token", required=True, type=str) parser.add_argument("--sell-token-decimals", help="Number of decimals for the sell token", type=int, default=18) parser.add_argument("--old-sell-token-address", help="Ethereum address of the old sell token", required=False, 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.buy_token_address = Address(self.arguments.buy_token_address) self.sell_token_address = Address(self.arguments.sell_token_address) self.old_sell_token_address = Address( self.arguments.old_sell_token_address ) if self.arguments.old_sell_token_address else None self.sell_token_addresses = list( filter(lambda address: address is not None, [self.sell_token_address, self.old_sell_token_address])) self.market_maker_address = Address( self.arguments.market_maker_address) self.exchange = ZrxExchange(web3=self.web3, address=Address( self.arguments.exchange_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.exchange.past_fill( self.arguments.past_blocks, {'maker': self.market_maker_address.address}) trades = zrx_trades(self.infura, self.market_maker_address, self.arguments.buy_token, self.buy_token_address, self.arguments.buy_token_decimals, self.arguments.sell_token, self.sell_token_addresses, self.arguments.sell_token_decimals, 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)
class RadarRelayMarketMakerChart: """Tool to analyze the RadarRelay Market Maker keeper performance.""" def __init__(self, args: list): parser = argparse.ArgumentParser(prog='radarrelay-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("--exchange-address", help="Ethereum address of the 0x contract", required=True, type=str) parser.add_argument("--sai-address", help="Ethereum address of the SAI token", required=True, type=str) parser.add_argument("--weth-address", help="Ethereum address of the WETH 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.weth_address = Address(self.arguments.weth_address) self.market_maker_address = Address(self.arguments.market_maker_address) self.exchange = ZrxExchange(web3=self.web3, address=Address(self.arguments.exchange_address)) if self.arguments.output: import matplotlib matplotlib.use('Agg') def main(self): past_trade = self.exchange.past_fill(self.arguments.past_blocks) def sell_trades() -> List[Trade]: return list(map(lambda log_take: Trade(self.get_event_timestamp(log_take), log_take.filled_buy_amount / log_take.filled_pay_amount, log_take.filled_buy_amount, False, True), filter(lambda log_take: log_take.maker == self.market_maker_address and log_take.buy_token == self.sai_address and log_take.pay_token == self.weth_address, past_trade))) def buy_trades() -> List[Trade]: return list(map(lambda log_take: Trade(self.get_event_timestamp(log_take), log_take.filled_pay_amount / log_take.filled_buy_amount, log_take.filled_pay_amount, True, False), filter(lambda log_take: log_take.maker == self.market_maker_address and log_take.buy_token == self.weth_address and log_take.pay_token == self.sai_address, past_trade))) 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 ZrxMarketMakerTrades: """Tool to list historical trades for the 0x market maker keeper.""" def __init__(self, args: list): parser = argparse.ArgumentParser(prog='0x-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("--exchange-address", help="Ethereum address of the 0x contract", required=True, type=str) parser.add_argument( "--exchange-name", help="Exchange name for including in the JSON file", required=True, type=str) parser.add_argument("--buy-token", help="Name of the buy token", required=True, type=str) parser.add_argument("--buy-token-address", help="Ethereum address of the buy token", required=True, type=str) parser.add_argument("--buy-token-decimals", help="Number of decimals for the buy token", type=int, default=18) parser.add_argument("--sell-token", help="Name of the sell token", required=True, type=str) parser.add_argument("--sell-token-address", help="Ethereum address of the sell token", required=True, type=str) parser.add_argument("--sell-token-decimals", help="Number of decimals for the sell token", type=int, default=18) parser.add_argument("--old-sell-token-address", help="Ethereum address of the old sell token", required=False, 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.buy_token_address = Address(self.arguments.buy_token_address) self.sell_token_address = Address(self.arguments.sell_token_address) self.old_sell_token_address = Address( self.arguments.old_sell_token_address ) if self.arguments.old_sell_token_address else None self.sell_token_addresses = list( filter(lambda address: address is not None, [self.sell_token_address, self.old_sell_token_address])) self.market_maker_address = Address( self.arguments.market_maker_address) self.exchange = ZrxExchange(web3=self.web3, address=Address( self.arguments.exchange_address)) logging.basicConfig( format='%(asctime)-15s %(levelname)-8s %(message)s', level=logging.INFO) logging.getLogger("filelock").setLevel(logging.WARNING) def main(self): past_fills = self.exchange.past_fill( self.arguments.past_blocks, {'maker': self.market_maker_address.address}) trades = zrx_trades(self.infura, self.market_maker_address, self.arguments.buy_token, self.buy_token_address, self.arguments.buy_token_decimals, self.arguments.sell_token, self.sell_token_addresses, self.arguments.sell_token_decimals, past_fills, self.arguments.exchange_name) trades = sort_trades(trades) if self.arguments.text: text_trades(self.arguments.buy_token, self.arguments.sell_token, trades, self.arguments.output, include_taker=True) if self.arguments.json: json_trades(trades, self.arguments.output, include_taker=True)