def __init__(self, args: list, **kwargs): parser = argparse.ArgumentParser(prog='gateio-market-maker-keeper') parser.add_argument("--gateio-api-server", type=str, default="https://data.gate.io", help="Address of the Gate.io API server (default: 'https://data.gate.io')") parser.add_argument("--gateio-api-key", type=str, required=True, help="API key for the Gate.io API") parser.add_argument("--gateio-secret-key", type=str, required=True, help="Secret key for the Gate.io API") parser.add_argument("--gateio-timeout", type=float, default=9.5, help="Timeout for accessing the Gate.io API (in seconds, default: 9.5)") parser.add_argument("--pair", type=str, required=True, help="Token pair on which the keeper should operate") parser.add_argument("--config", type=str, required=True, help="Buy/sell bands configuration file") parser.add_argument("--price-feed", type=str, help="Source of price feed") parser.add_argument("--price-feed-expiry", type=int, default=120, help="Maximum age of the price feed (in seconds, default: 120)") parser.add_argument("--debug", dest='debug', action='store_true', help="Enable debug output") self.arguments = parser.parse_args(args) logging.basicConfig(format='%(asctime)-15s %(levelname)-8s %(message)s', level=(logging.DEBUG if self.arguments.debug else logging.INFO)) logging.getLogger('urllib3.connectionpool').setLevel(logging.INFO) logging.getLogger('requests.packages.urllib3.connectionpool').setLevel(logging.INFO) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments.price_feed, self.arguments.price_feed_expiry) self.gateio_api = GateIOApi(api_server=self.arguments.gateio_api_server, api_key=self.arguments.gateio_api_key, secret_key=self.arguments.gateio_secret_key, timeout=self.arguments.gateio_timeout) self._last_order_creation = 0
def __init__(self, args: list): parser = argparse.ArgumentParser(prog='gateio-market-maker-keeper') parser.add_argument("--gateio-api-server", type=str, default="https://data.gate.io", help="Address of the Gate.io API server (default: 'https://data.gate.io')") parser.add_argument("--gateio-api-key", type=str, required=True, help="API key for the Gate.io API") parser.add_argument("--gateio-secret-key", type=str, required=True, help="Secret key for the Gate.io API") parser.add_argument("--gateio-timeout", type=float, default=9.5, help="Timeout for accessing the Gate.io API (in seconds, default: 9.5)") parser.add_argument("--pair", type=str, required=True, help="Token pair (sell/buy) on which the keeper will operate") parser.add_argument("--config", type=str, required=True, help="Bands configuration file") parser.add_argument("--price-feed", type=str, required=True, help="Source of price feed") parser.add_argument("--price-feed-expiry", type=int, default=120, help="Maximum age of the price feed (in seconds, default: 120)") parser.add_argument("--spread-feed", type=str, help="Source of spread feed") parser.add_argument("--spread-feed-expiry", type=int, default=3600, help="Maximum age of the spread feed (in seconds, default: 3600)") parser.add_argument("--order-history", type=str, help="Endpoint to report active orders to") parser.add_argument("--order-history-every", type=int, default=30, help="Frequency of reporting active orders (in seconds, default: 30)") parser.add_argument("--debug", dest='debug', action='store_true', help="Enable debug output") self.arguments = parser.parse_args(args) setup_logging(self.arguments) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments) self.spread_feed = create_spread_feed(self.arguments) self.order_history_reporter = create_order_history_reporter(self.arguments) self.history = History() self.gateio_api = GateIOApi(api_server=self.arguments.gateio_api_server, api_key=self.arguments.gateio_api_key, secret_key=self.arguments.gateio_secret_key, timeout=self.arguments.gateio_timeout) self._last_order_creation = 0
# (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import sys from pyexchange.gateio import GateIOApi from pymaker.numeric import Wad gate = GateIOApi('https://data.gate.io', sys.argv[1], sys.argv[2], 9.5) # print(gate.pairs()) # print(gate.tickers()) # print(gate.ticker('mkr_eth')) # print(gate.orderBooks()) # print(gate.order_book('btc_usdt')) # print(gate.get_balances()) #{'result': 'true', 'message': 'Success', 'code': 0, 'orderNumber': 368042106} # print(gate.place_order('mkr_eth', False, Wad.from_number(1.35), Wad.from_number(0.01))) # print(gate.place_order('mkr_eth', True, Wad.from_number(1.45), Wad.from_number(0.01))) # print(gate.sell('etc_btc','0.001','123')) # print(gate.getOrder('267040896','eth_btc')) # print(gate.get_orders('mkr_eth')) # for order in gate.get_orders('mkr_eth'): # print(gate.cancel_order('mkr_eth', order.order_id))
def __init__(self, args: list): parser = argparse.ArgumentParser(prog='gateio-market-maker-keeper') parser.add_argument( "--gateio-api-server", type=str, default="https://data.gate.io", help= "Address of the Gate.io API server (default: 'https://data.gate.io')" ) parser.add_argument("--gateio-api-key", type=str, required=True, help="API key for the Gate.io API") parser.add_argument("--gateio-secret-key", type=str, required=True, help="Secret key for the Gate.io API") parser.add_argument( "--gateio-timeout", type=float, default=9.5, help= "Timeout for accessing the Gate.io API (in seconds, default: 9.5)") parser.add_argument( "--pair", type=str, required=True, help="Token pair (sell/buy) on which the keeper will operate") parser.add_argument("--config", type=str, required=True, help="Bands configuration file") parser.add_argument("--price-feed", type=str, required=True, help="Source of price feed") parser.add_argument( "--price-feed-expiry", type=int, default=120, help="Maximum age of the price feed (in seconds, default: 120)") parser.add_argument("--spread-feed", type=str, help="Source of spread feed") parser.add_argument( "--spread-feed-expiry", type=int, default=3600, help="Maximum age of the spread feed (in seconds, default: 3600)") parser.add_argument("--order-history", type=str, help="Endpoint to report active orders to") parser.add_argument( "--order-history-every", type=int, default=30, help= "Frequency of reporting active orders (in seconds, default: 30)") parser.add_argument( "--refresh-frequency", type=int, default=3, help="Order book refresh frequency (in seconds, default: 3)") parser.add_argument("--debug", dest='debug', action='store_true', help="Enable debug output") self.arguments = parser.parse_args(args) setup_logging(self.arguments) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments) self.spread_feed = create_spread_feed(self.arguments) self.order_history_reporter = create_order_history_reporter( self.arguments) self.history = History() self.gateio_api = GateIOApi( api_server=self.arguments.gateio_api_server, api_key=self.arguments.gateio_api_key, secret_key=self.arguments.gateio_secret_key, timeout=self.arguments.gateio_timeout) self.order_book_manager = OrderBookManager( refresh_frequency=self.arguments.refresh_frequency) self.order_book_manager.get_orders_with( lambda: self.gateio_api.get_orders(self.pair())) self.order_book_manager.get_balances_with( lambda: self.gateio_api.get_balances()) self.order_book_manager.cancel_orders_with( lambda order: self.gateio_api.cancel_order(self.pair(), order. order_id)) self.order_book_manager.enable_history_reporting( self.order_history_reporter, self.our_buy_orders, self.our_sell_orders) self.order_book_manager.start() self._last_order_creation = 0
class GateIOMarketMakerKeeper: """Keeper acting as a market maker on Gate.io.""" logger = logging.getLogger() def __init__(self, args: list): parser = argparse.ArgumentParser(prog='gateio-market-maker-keeper') parser.add_argument( "--gateio-api-server", type=str, default="https://data.gate.io", help= "Address of the Gate.io API server (default: 'https://data.gate.io')" ) parser.add_argument("--gateio-api-key", type=str, required=True, help="API key for the Gate.io API") parser.add_argument("--gateio-secret-key", type=str, required=True, help="Secret key for the Gate.io API") parser.add_argument( "--gateio-timeout", type=float, default=9.5, help= "Timeout for accessing the Gate.io API (in seconds, default: 9.5)") parser.add_argument( "--pair", type=str, required=True, help="Token pair (sell/buy) on which the keeper will operate") parser.add_argument("--config", type=str, required=True, help="Bands configuration file") parser.add_argument("--price-feed", type=str, required=True, help="Source of price feed") parser.add_argument( "--price-feed-expiry", type=int, default=120, help="Maximum age of the price feed (in seconds, default: 120)") parser.add_argument("--spread-feed", type=str, help="Source of spread feed") parser.add_argument( "--spread-feed-expiry", type=int, default=3600, help="Maximum age of the spread feed (in seconds, default: 3600)") parser.add_argument("--order-history", type=str, help="Endpoint to report active orders to") parser.add_argument( "--order-history-every", type=int, default=30, help= "Frequency of reporting active orders (in seconds, default: 30)") parser.add_argument( "--refresh-frequency", type=int, default=3, help="Order book refresh frequency (in seconds, default: 3)") parser.add_argument("--debug", dest='debug', action='store_true', help="Enable debug output") self.arguments = parser.parse_args(args) setup_logging(self.arguments) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments) self.spread_feed = create_spread_feed(self.arguments) self.order_history_reporter = create_order_history_reporter( self.arguments) self.history = History() self.gateio_api = GateIOApi( api_server=self.arguments.gateio_api_server, api_key=self.arguments.gateio_api_key, secret_key=self.arguments.gateio_secret_key, timeout=self.arguments.gateio_timeout) self.order_book_manager = OrderBookManager( refresh_frequency=self.arguments.refresh_frequency) self.order_book_manager.get_orders_with( lambda: self.gateio_api.get_orders(self.pair())) self.order_book_manager.get_balances_with( lambda: self.gateio_api.get_balances()) self.order_book_manager.cancel_orders_with( lambda order: self.gateio_api.cancel_order(self.pair(), order. order_id)) self.order_book_manager.enable_history_reporting( self.order_history_reporter, self.our_buy_orders, self.our_sell_orders) self.order_book_manager.start() self._last_order_creation = 0 def main(self): with Lifecycle() as lifecycle: lifecycle.initial_delay(10) lifecycle.every(1, self.synchronize_orders) lifecycle.on_shutdown(self.shutdown) def shutdown(self): self.order_book_manager.cancel_all_orders() def pair(self): return self.arguments.pair.lower() def token_sell(self) -> str: return self.arguments.pair.split('_')[0].upper() def token_buy(self) -> str: return self.arguments.pair.split('_')[1].upper() def our_available_balance(self, our_balances: dict, token: str) -> Wad: try: return Wad.from_number(our_balances['available'][token]) except KeyError: return Wad(0) def our_sell_orders(self, our_orders: list) -> list: return list(filter(lambda order: order.is_sell, our_orders)) def our_buy_orders(self, our_orders: list) -> list: return list(filter(lambda order: not order.is_sell, our_orders)) def synchronize_orders(self): bands = Bands.read(self.bands_config, self.spread_feed, self.history) order_book = self.order_book_manager.get_order_book() target_price = self.price_feed.get_price() # Cancel orders cancellable_orders = bands.cancellable_orders( our_buy_orders=self.our_buy_orders(order_book.orders), our_sell_orders=self.our_sell_orders(order_book.orders), target_price=target_price) if len(cancellable_orders) > 0: self.order_book_manager.cancel_orders(cancellable_orders) return # Do not place new orders if order book state is not confirmed if order_book.orders_being_placed or order_book.orders_being_cancelled: self.logger.debug( "Order book is in progress, not placing new orders") return # Place new orders new_orders = bands.new_orders( our_buy_orders=self.our_buy_orders(order_book.orders), our_sell_orders=self.our_sell_orders(order_book.orders), our_buy_balance=self.our_available_balance(order_book.balances, self.token_buy()), our_sell_balance=self.our_available_balance( order_book.balances, self.token_sell()), target_price=target_price)[0] if len(new_orders) > 0: if self.can_create_orders(): self.place_orders(new_orders) self.register_order_creation() else: self.logger.info( "Too little time elapsed from last order creation, waiting..." ) # Unfortunately the gate.io API does not immediately reflect the fact that our orders have # been placed. In order to avoid placing orders twice we explicitly wait some time here. def can_create_orders(self) -> bool: return time.time() - self._last_order_creation > 15 def register_order_creation(self): self._last_order_creation = time.time() def place_orders(self, new_orders: List[NewOrder]): def place_order_function(new_order_to_be_placed): amount = new_order_to_be_placed.pay_amount if new_order_to_be_placed.is_sell else new_order_to_be_placed.buy_amount order_id = self.gateio_api.place_order( self.pair(), new_order_to_be_placed.is_sell, new_order_to_be_placed.price, amount) return Order(order_id=order_id, timestamp=0, pair=self.pair(), is_sell=new_order_to_be_placed.is_sell, price=new_order_to_be_placed.price, amount=amount, amount_symbol=self.token_sell(), money=amount * new_order_to_be_placed.price, money_symbol=self.token_buy(), initial_amount=amount, filled_amount=Wad(0)) for new_order in new_orders: self.order_book_manager.place_order( lambda new_order=new_order: place_order_function(new_order))
def __init__(self, args: list, **kwargs): parser = argparse.ArgumentParser(prog='gateio-market-maker-keeper') parser.add_argument( "--gateio-api-server", type=str, default="https://data.gate.io", help= "Address of the Gate.io API server (default: 'https://data.gate.io')" ) parser.add_argument("--gateio-api-key", type=str, required=True, help="API key for the Gate.io API") parser.add_argument("--gateio-secret-key", type=str, required=True, help="Secret key for the Gate.io API") parser.add_argument( "--gateio-timeout", type=float, default=9.5, help= "Timeout for accessing the Gate.io API (in seconds, default: 9.5)") parser.add_argument( "--pair", type=str, required=True, help="Token pair (sell/buy) on which the keeper will operate") parser.add_argument("--config", type=str, required=True, help="Bands configuration file") parser.add_argument("--price-feed", type=str, required=True, help="Source of price feed") parser.add_argument( "--price-feed-expiry", type=int, default=120, help="Maximum age of the price feed (in seconds, default: 120)") parser.add_argument("--debug", dest='debug', action='store_true', help="Enable debug output") self.arguments = parser.parse_args(args) setup_logging(self.arguments) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed( self.arguments.price_feed, self.arguments.price_feed_expiry) self.gateio_api = GateIOApi( api_server=self.arguments.gateio_api_server, api_key=self.arguments.gateio_api_key, secret_key=self.arguments.gateio_secret_key, timeout=self.arguments.gateio_timeout) self._last_order_creation = 0
class GateIOMarketMakerKeeper: """Keeper acting as a market maker on Gate.io.""" logger = logging.getLogger() def __init__(self, args: list, **kwargs): parser = argparse.ArgumentParser(prog='gateio-market-maker-keeper') parser.add_argument( "--gateio-api-server", type=str, default="https://data.gate.io", help= "Address of the Gate.io API server (default: 'https://data.gate.io')" ) parser.add_argument("--gateio-api-key", type=str, required=True, help="API key for the Gate.io API") parser.add_argument("--gateio-secret-key", type=str, required=True, help="Secret key for the Gate.io API") parser.add_argument( "--gateio-timeout", type=float, default=9.5, help= "Timeout for accessing the Gate.io API (in seconds, default: 9.5)") parser.add_argument( "--pair", type=str, required=True, help="Token pair (sell/buy) on which the keeper will operate") parser.add_argument("--config", type=str, required=True, help="Bands configuration file") parser.add_argument("--price-feed", type=str, required=True, help="Source of price feed") parser.add_argument( "--price-feed-expiry", type=int, default=120, help="Maximum age of the price feed (in seconds, default: 120)") parser.add_argument("--debug", dest='debug', action='store_true', help="Enable debug output") self.arguments = parser.parse_args(args) setup_logging(self.arguments) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed( self.arguments.price_feed, self.arguments.price_feed_expiry) self.gateio_api = GateIOApi( api_server=self.arguments.gateio_api_server, api_key=self.arguments.gateio_api_key, secret_key=self.arguments.gateio_secret_key, timeout=self.arguments.gateio_timeout) self._last_order_creation = 0 def main(self): with Lifecycle() as lifecycle: lifecycle.on_startup(self.startup) lifecycle.every(10, self.synchronize_orders) lifecycle.on_shutdown(self.shutdown) def startup(self): self.our_orders() self.our_balances() self.logger.info(f"Gate.io API key seems to be valid") self.logger.info( f"Keeper configured to work on the '{self.pair()}' pair") def shutdown(self): self.gateio_api.cancel_all_orders(self.pair()) def pair(self): return self.arguments.pair.lower() def token_sell(self) -> str: return self.arguments.pair.split('_')[0].upper() def token_buy(self) -> str: return self.arguments.pair.split('_')[1].upper() def our_balances(self) -> dict: return self.gateio_api.get_balances() def our_available_balance(self, our_balances: dict, token: str) -> Wad: try: return Wad.from_number(our_balances['available'][token]) except KeyError: return Wad(0) def our_orders(self) -> list: return self.gateio_api.get_orders(self.pair()) def our_sell_orders(self, our_orders: list) -> list: return list(filter(lambda order: order.is_sell, our_orders)) def our_buy_orders(self, our_orders: list) -> list: return list(filter(lambda order: not order.is_sell, our_orders)) def synchronize_orders(self): bands = Bands(self.bands_config) our_balances = self.our_balances() our_orders = self.our_orders() target_price = self.price_feed.get_price() if target_price is None: self.logger.warning( "Cancelling all orders as no price feed available.") self.cancel_orders(our_orders) return # Cancel orders cancellable_orders = bands.cancellable_orders( our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), target_price=target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders) return # Place new orders new_orders = bands.new_orders( our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), our_buy_balance=self.our_available_balance(our_balances, self.token_buy()), our_sell_balance=self.our_available_balance( our_balances, self.token_sell()), target_price=target_price)[0] if len(new_orders) > 0: if self.can_create_orders(): self.create_orders(new_orders) self.register_order_creation() else: self.logger.info( "Too little time elapsed from last order creation, waiting..." ) # Unfortunately the gate.io API does not immediately reflect the fact that our orders have # been placed. In order to avoid placing orders twice we explicitly wait some time here. def can_create_orders(self) -> bool: return time.time() - self._last_order_creation > 15 def register_order_creation(self): self._last_order_creation = time.time() def cancel_orders(self, orders: List[Order]): for order in orders: self.gateio_api.cancel_order(self.pair(), order.order_id) def create_orders(self, orders: List[NewOrder]): for order in orders: amount = order.pay_amount if order.is_sell else order.buy_amount self.gateio_api.place_order(self.pair(), order.is_sell, order.price, amount)
class GateIOMarketMakerKeeper: """Keeper acting as a market maker on Gate.io.""" logger = logging.getLogger() def __init__(self, args: list): parser = argparse.ArgumentParser(prog='gateio-market-maker-keeper') parser.add_argument("--gateio-api-server", type=str, default="https://data.gate.io", help="Address of the Gate.io API server (default: 'https://data.gate.io')") parser.add_argument("--gateio-api-key", type=str, required=True, help="API key for the Gate.io API") parser.add_argument("--gateio-secret-key", type=str, required=True, help="Secret key for the Gate.io API") parser.add_argument("--gateio-timeout", type=float, default=9.5, help="Timeout for accessing the Gate.io API (in seconds, default: 9.5)") parser.add_argument("--pair", type=str, required=True, help="Token pair (sell/buy) on which the keeper will operate") parser.add_argument("--config", type=str, required=True, help="Bands configuration file") parser.add_argument("--price-feed", type=str, required=True, help="Source of price feed") parser.add_argument("--price-feed-expiry", type=int, default=120, help="Maximum age of the price feed (in seconds, default: 120)") parser.add_argument("--spread-feed", type=str, help="Source of spread feed") parser.add_argument("--spread-feed-expiry", type=int, default=3600, help="Maximum age of the spread feed (in seconds, default: 3600)") parser.add_argument("--order-history", type=str, help="Endpoint to report active orders to") parser.add_argument("--order-history-every", type=int, default=30, help="Frequency of reporting active orders (in seconds, default: 30)") parser.add_argument("--debug", dest='debug', action='store_true', help="Enable debug output") self.arguments = parser.parse_args(args) setup_logging(self.arguments) self.bands_config = ReloadableConfig(self.arguments.config) self.price_feed = PriceFeedFactory().create_price_feed(self.arguments) self.spread_feed = create_spread_feed(self.arguments) self.order_history_reporter = create_order_history_reporter(self.arguments) self.history = History() self.gateio_api = GateIOApi(api_server=self.arguments.gateio_api_server, api_key=self.arguments.gateio_api_key, secret_key=self.arguments.gateio_secret_key, timeout=self.arguments.gateio_timeout) self._last_order_creation = 0 def main(self): with Lifecycle() as lifecycle: lifecycle.on_startup(self.startup) lifecycle.every(10, self.synchronize_orders) lifecycle.on_shutdown(self.shutdown) def startup(self): self.our_orders() self.our_balances() self.logger.info(f"Gate.io API key seems to be valid") self.logger.info(f"Keeper configured to work on the '{self.pair()}' pair") @retry(delay=5, logger=logger) def shutdown(self): self.gateio_api.cancel_all_orders(self.pair()) def pair(self): return self.arguments.pair.lower() def token_sell(self) -> str: return self.arguments.pair.split('_')[0].upper() def token_buy(self) -> str: return self.arguments.pair.split('_')[1].upper() def our_balances(self) -> dict: return self.gateio_api.get_balances() def our_available_balance(self, our_balances: dict, token: str) -> Wad: try: return Wad.from_number(our_balances['available'][token]) except KeyError: return Wad(0) def our_orders(self) -> list: return self.gateio_api.get_orders(self.pair()) def our_sell_orders(self, our_orders: list) -> list: return list(filter(lambda order: order.is_sell, our_orders)) def our_buy_orders(self, our_orders: list) -> list: return list(filter(lambda order: not order.is_sell, our_orders)) def synchronize_orders(self): bands = Bands(self.bands_config, self.spread_feed, self.history) our_balances = self.our_balances() our_orders = self.our_orders() target_price = self.price_feed.get_price() # Cancel orders cancellable_orders = bands.cancellable_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), target_price=target_price) if len(cancellable_orders) > 0: self.cancel_orders(cancellable_orders) return # Place new orders new_orders = bands.new_orders(our_buy_orders=self.our_buy_orders(our_orders), our_sell_orders=self.our_sell_orders(our_orders), our_buy_balance=self.our_available_balance(our_balances, self.token_buy()), our_sell_balance=self.our_available_balance(our_balances, self.token_sell()), target_price=target_price)[0] if len(new_orders) > 0: if self.can_create_orders(): self.place_orders(new_orders) self.register_order_creation() else: self.logger.info("Too little time elapsed from last order creation, waiting...") # Unfortunately the gate.io API does not immediately reflect the fact that our orders have # been placed. In order to avoid placing orders twice we explicitly wait some time here. def can_create_orders(self) -> bool: return time.time() - self._last_order_creation > 15 def register_order_creation(self): self._last_order_creation = time.time() def cancel_orders(self, orders: List[Order]): for order in orders: self.gateio_api.cancel_order(self.pair(), order.order_id) def place_orders(self, new_orders: List[NewOrder]): for new_order in new_orders: amount = new_order.pay_amount if new_order.is_sell else new_order.buy_amount self.gateio_api.place_order(self.pair(), new_order.is_sell, new_order.price, amount)