# (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.kucoin import KucoinApi from pymaker import Wad kucoin = KucoinApi('https://api.kucoin.com', sys.argv[1], sys.argv[2], 9.5) # print("USER INFO") # print(kucoinNew.get_user_info()) # print("Markwets INFO") # print(kucoinNew.get_markets()) # print("BALANCES") # print(kucoin.get_balances()) # print("DAI balance") # print(kucoin.get_balance("DAI")) # print("ETH balance") # print(kucoin.get_balance("ETH")) # print("ETH-DAI ticker") # print(kucoin.ticker("ETH-DAI")) # print("ETH-DAI order book") # print(kucoin.order_book("USDT-DAI"))
class KucoinMarketMakerKeeper: """Keeper acting as a market maker on kucoin.""" logger = logging.getLogger() def __init__(self, args: list): parser = argparse.ArgumentParser(prog='kucoin-market-maker-keeper') parser.add_argument("--kucoin-api-server", type=str, default="https://api.kucoin.com", help="Address of the kucoin API server (default: 'https://api.kucoin.com')") parser.add_argument("--kucoin-api-key", type=str, required=True, help="API key for the kucoin API") parser.add_argument("--kucoin-secret-key", type=str, required=True, help="Secret key for the kucoin API") parser.add_argument("--kucoin-timeout", type=float, default=9.5, help="Timeout for accessing the kucoin 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("--control-feed", type=str, help="Source of control feed") parser.add_argument("--control-feed-expiry", type=int, default=86400, help="Maximum age of the control feed (in seconds, default: 86400)") 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.control_feed = create_control_feed(self.arguments) self.order_history_reporter = create_order_history_reporter(self.arguments) self.history = History() self.kucoin_api = KucoinApi(api_server=self.arguments.kucoin_api_server, api_key=self.arguments.kucoin_api_key, secret_key=self.arguments.kucoin_secret_key, timeout=self.arguments.kucoin_timeout) self.order_book_manager = OrderBookManager(refresh_frequency=self.arguments.refresh_frequency) self.order_book_manager.get_orders_with(lambda: self.kucoin_api.get_orders(self.pair())) self.order_book_manager.get_balances_with(lambda: self.kucoin_api.get_balances()) self.order_book_manager.cancel_orders_with(lambda order: self.kucoin_api.cancel_order(order.order_id, order.is_sell, self.pair())) self.order_book_manager.enable_history_reporting(self.order_history_reporter, self.our_buy_orders, self.our_sell_orders) self.order_book_manager.start() def main(self): with Lifecycle() as lifecycle: lifecycle.initial_delay(10) lifecycle.on_startup(self.startup) lifecycle.every(1, self.synchronize_orders) lifecycle.on_shutdown(self.shutdown) def startup(self): # Get maximum number of decimals for prices and amounts. self.price_precision = self.kucoin_api.get_coin_info(self.token_buy())['tradePrecision'] self.amount_precision = self.kucoin_api.get_coin_info(self.token_sell())['tradePrecision'] def shutdown(self): self.order_book_manager.cancel_all_orders() def pair(self): return self.arguments.pair.upper() 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: token_balances = list(filter(lambda coin: coin['coinType'].upper() == token, our_balances)) if token_balances: return Wad.from_number(self.round_down(token_balances[0]['balance'], self.amount_precision)) else: 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.control_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] self.place_orders(new_orders) def place_orders(self, new_orders: List[NewOrder]): def place_order_function(new_order_to_be_placed): price = round(new_order_to_be_placed.price, self.price_precision) amount = new_order_to_be_placed.pay_amount if new_order_to_be_placed.is_sell else new_order_to_be_placed.buy_amount amount = round(amount, self.amount_precision) order_id = self.kucoin_api.place_order(self.pair(), new_order_to_be_placed.is_sell, price, amount) return Order(order_id=order_id, pair=self.pair(), is_sell=new_order_to_be_placed.is_sell, price=price, amount=amount) for new_order in new_orders: self.order_book_manager.place_order(lambda new_order=new_order: place_order_function(new_order)) @staticmethod def round_down(num, precision): multiplier = pow(10, precision) return floor(num * multiplier) / multiplier
def __init__(self, args: list): parser = argparse.ArgumentParser(prog='kucoin-market-maker-keeper') parser.add_argument("--kucoin-api-server", type=str, default="https://api.kucoin.com", help="Address of the kucoin API server (default: 'https://api.kucoin.com')") parser.add_argument("--kucoin-api-key", type=str, required=True, help="API key for the kucoin API") parser.add_argument("--kucoin-secret-key", type=str, required=True, help="Secret key for the kucoin API") parser.add_argument("--kucoin-timeout", type=float, default=9.5, help="Timeout for accessing the kucoin 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("--control-feed", type=str, help="Source of control feed") parser.add_argument("--control-feed-expiry", type=int, default=86400, help="Maximum age of the control feed (in seconds, default: 86400)") 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.control_feed = create_control_feed(self.arguments) self.order_history_reporter = create_order_history_reporter(self.arguments) self.history = History() self.kucoin_api = KucoinApi(api_server=self.arguments.kucoin_api_server, api_key=self.arguments.kucoin_api_key, secret_key=self.arguments.kucoin_secret_key, timeout=self.arguments.kucoin_timeout) self.order_book_manager = OrderBookManager(refresh_frequency=self.arguments.refresh_frequency) self.order_book_manager.get_orders_with(lambda: self.kucoin_api.get_orders(self.pair())) self.order_book_manager.get_balances_with(lambda: self.kucoin_api.get_balances()) self.order_book_manager.cancel_orders_with(lambda order: self.kucoin_api.cancel_order(order.order_id, order.is_sell, self.pair())) self.order_book_manager.enable_history_reporting(self.order_history_reporter, self.our_buy_orders, self.our_sell_orders) self.order_book_manager.start()
# (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.kucoin import KucoinApi from pymaker import Wad kucoin = KucoinApi('https://openapi-v2.kucoin.com', sys.argv[1], sys.argv[2], sys.argv[3], 9.5) # print("USER INFO") # print(kucoinNew.get_user_info()) # print("Markwets INFO") # print(kucoinNew.get_markets()) # print("BALANCES") # print(kucoin.get_balances()) # print("DAI balance") # print(kucoin.get_balance("DAI")) # print("ETH balance") # print(kucoin.get_balance("ETH")) # print("ETH-DAI ticker") # print(kucoin.ticker("ETH-DAI")) # print("ETH-DAI order book") # print(kucoin.order_book("USDT-DAI"))