[
  {
    "path": ".gitignore",
    "content": "# Personal setting (Henrison)\nsetting.json\nftx.log\noutput.log"
  },
  {
    "path": "README.md",
    "content": "\n# FTX Grid Trading Bot\n\nThe program was designed to run the Grid Trading Strategy in [FTX exchange](https://ftx.com/#a=1815639)\n \nGrid trading strategy can follow [here](https://www.gridtradingcourse.com/articles/what-is-grid-trading.php).\n\n\nIt requires python 3.x and the following Python packages:\n* [ccxt](https://github.com/ccxt/ccxt)\n* [simplejson](https://pypi.org/project/simplejson/)\n```\npip3 install ccxt simplejson\n```\n![](https://github.com/HenrisonTao/ftx_grid_trading_bot/blob/master/sample.png)\n\n## Getting Started\nThe program is suggested to run in the Linux platform; also, you need to edit some parameters before program start. Follow the behind steps. \n**you should prepare the enough USD and spot for grid trading buying and selling . Futures do not need to prepare enough spot to sell.\n1. Edit some config settings in `setting.json.example` and rename it to `setting.json`.\n2. Run program\n```\nbash ./start.sh\n```\n"
  },
  {
    "path": "main.py",
    "content": "# coding=utf-8\n\nimport ccxt\nimport datetime\nimport time\nimport os\nimport sys\nimport simplejson as json\n# import random\n# import threading\n\nCOLOR_RESET = \"\\033[0;0m\"\nCOLOR_GREEN = \"\\033[0;32m\"\nCOLOR_RED = \"\\033[1;31m\"\nCOLOR_BLUE = \"\\033[1;34m\"\nCOLOR_WHITE = \"\\033[1;37m\"\nLOGFILE=\"\"\n\nclass Oreder_Info:\n    def __init__(self):\n        self.done=False\n        self.side=None\n        self.id=0\n\nclass Grid_trader:\n    order_list=[]\n\n    def __init__(self,exchange,symbol,grid_level=0,lower_price=0.0,upper_price=0.0,amount=0):\n        self.symbol = symbol\n        self.exchange=exchange\n        self.order_min_inteval= self.exchange.markets[self.symbol][\"info\"][\"priceIncrement\"]\n        self.grid_level=grid_level\n        self.upper_price=upper_price\n        self.lower_price=lower_price\n        self.amount=amount\n        self.inteval_profit=(self.upper_price-self.lower_price) / self.grid_level\n        pass\n\n    def place_order_init(self):\n        #start cal level and place grid oreder\n        for i in range(self.grid_level + 1): #  n+1 lines make n grid\n            price = self.lower_price + i * self.inteval_profit\n            bid_price, ask_price = self.send_request(\"get_bid_ask_price\")\n            order = Oreder_Info()\n            if  price < ask_price : \n                order.id = self.send_request(\"place_order\",\"buy\",price)\n                log(\"place buy order id = \" + str(order.id) + \" in \"+ str(price))\n            else:\n                order.id = self.send_request(\"place_order\",\"sell\",price)\n                log(\"place sell order id = \" + str(order.id) + \" in \"+ str(price))\n            self.order_list.append(order)\n    \n    def loop_job(self):\n        for order in self.order_list:\n            order_info = self.send_request(\"get_order\",order.id)\n            side = order_info[\"side\"]\n            if order_info[\"status\"] == \"closed\":\n                new_order_price = 0.0\n                old_order_id = order_info[\"id\"]\n                bid_price, ask_price = self.send_request(\"get_bid_ask_price\")\n                msg = side + \" order id : \" + str(old_order_id)+\" : \" + str(order_info[\"price\"]) + \" completed , put \"\n                if side == \"buy\" :\n                    new_order_price = float(order_info[\"price\"]) + self.inteval_profit \n                    order.id = self.send_request(\"place_order\",\"sell\",new_order_price)\n                    msg = msg + \"sell\"\n                    log(msg)\n                else:\n                    new_order_price = float(order_info[\"price\"]) - self.inteval_profit\n                    order.id = self.send_request(\"place_order\",\"buy\",new_order_price)\n                    msg = msg + \"buy\"\n                msg = msg + \" order id : \" + str(order.id) + \" : \" + str(new_order_price)\n                log(msg)\n\n    def send_request(self,task,input1=None,input2=None):\n        tries = 3\n        for i in range(tries):\n            try:\n                if task == \"get_bid_ask_price\":\n                    ticker =self.exchange.fetch_ticker(self.symbol)\n                    return ticker[\"bid\"],  ticker[\"ask\"]\n\n                elif task == \"get_order\":\n                    return self.exchange.fetchOrder(input1)[\"info\"]\n\n                elif task == \"place_order\":\n                    #send_request(self,task,input1=side,input2=price)\n                    side = input1\n                    price = input2\n                    orderid=0\n                    if side ==\"buy\":\n                        orderid = self.exchange.create_limit_buy_order(self.symbol,self.amount,price )[\"info\"][\"id\"]\n                    else:\n                        orderid = self.exchange.create_limit_sell_order(self.symbol,self.amount,price )[\"info\"][\"id\"]\n                    return orderid\n\n                else:\n                    return None\n            except ccxt.NetworkError as e:\n                if i < tries - 1: # i is zero indexed\n                    log(\"NetworkError , try last \"+str(i) +\"chances\" + str(e))\n                    time.sleep(0.5)\n                    continue\n                else:\n                    log(str(e))\n                    raise\n            except ccxt.ExchangeError as e:\n                if i < tries - 1: # i is zero indexed\n                    log(str(e))\n                    time.sleep(0.5)\n                    continue\n                else:\n                    log(str(e))\n                    raise\n            break\n\ndef log(msg):\n    timestamp = datetime.datetime.now().strftime(\"%b %d %Y %H:%M:%S \")\n    s = \"[%s] %s:%s %s\" % (timestamp, COLOR_WHITE, COLOR_RESET, msg)\n    print(s)\n    try:\n        f = open(LOGFILE, \"a\")\n        f.write(s + \"\\n\")\n        f.close()\n    except:\n        pass\n\ndef read_setting():\n        with open('setting.json') as json_file:\n            return json.load(json_file)\n             \nconfig = read_setting()\nLOGFILE= config[\"LOGFILE\"]\n\nexchange  = ccxt.ftx({\n    'verbose': False,\n    'apiKey': config[\"apiKey\"],\n    'secret': config[\"secret\"],\n    'enableRateLimit': True,\n    'headers': {\n        'FTX-SUBACCOUNT': config[\"sub_account\"],\n    },\n})\n\nexchange_markets = exchange.load_markets()\n\nmain_job = Grid_trader(exchange,config[\"symbol\"],config[\"grid_level\"],config[\"lower_price\"],config[\"upper_price\"],config[\"amount\"])\nmain_job.place_order_init()\nwhile True:\n    print(\"Loop in :\",datetime.datetime.now())\n    main_job.loop_job()\n    time.sleep(1)\n"
  },
  {
    "path": "setting.json.example",
    "content": "{\n  \"LOGFILE\":\"ftx.log\",\n  \"apiKey\":\"your api key\",\n  \"secret\":\"your api secret\",\n  \"sub_account\":\"sub_account name\",\n  \"symbol\":\"SRM/USD\", \n  \"grid_level\":30,\n  \"lower_price\":2.0,\n  \"upper_price\":2.5,\n  \"amount\":1\n}"
  },
  {
    "path": "start.sh",
    "content": "#!/bin/bash\nrm ftx.log output.log\npython3 -u main.py > >(tee -a ./output.log) 2>&1"
  }
]