示例#1
0
    def sellOutOptions(self):
        """ METHOD SELLS OUT OPTIONS IF ONE DAY BEFORE EXPIRATION
        """

        open_positions = self.open_positions.find({
            "Trader": self.user["Name"],
            "Asset_Type": "OPTION"
        })

        dt = getDatetime()

        for position in open_positions:

            day_before = (position["Exp_Date"] -
                          timedelta(days=1)).strftime("%Y-%m-%d")

            if day_before == dt.strftime("%Y-%m-%d"):

                trade_data = {
                    "Symbol": position["Symbol"],
                    "Pre_Symbol": position["Pre_Symbol"],
                    "Side": "SELL_TO_CLOSE",
                    "Aggregation": position["Aggregation"],
                    "Strategy": position["Strategy"],
                    "Asset_Type": position["Asset_Type"],
                    "Exp_Date": position["Exp_Date"]
                }

                self.placeOrder(trade_data, position)
    def buyOrder(self, symbol):

        try:

            aggregation = symbol["Aggregation"]

            strategy = symbol["Strategy"]

            symbol = symbol["Symbol"]

            resp = self.tdameritrade.getQuote(symbol)

            price = float(resp[symbol]["lastPrice"])

            shares = 1

            obj = {
                "Symbol": symbol,
                "Qty": shares,
                "Buy_Price": price,
                "Date": getDatetime(),
                "Strategy": strategy,
                "Aggregation": aggregation
            }

            # ADD TO OPEN POSITIONS
            self.open_positions.insert_one(obj)

            # print("BUY")
            # pprint(obj)

        except Exception as e:

            print("SIM TRADER - buyOrder", e)
示例#3
0
    def sellOrder(self, symbol, position):

        try:

            aggregation = symbol["Aggregation"]

            strategy = symbol["Strategy"]

            symbol = symbol["Symbol"]

            qty = position["Qty"]

            position_price = position["Buy_Price"]

            position_date = position["Date"]

            resp = self.tdameritrade.getQuote(symbol)

            price = float(resp[symbol]["lastPrice"])

            sell_price = round(price * qty, 2)

            buy_price = round(position_price * qty, 2)

            if buy_price != 0:

                rov = round(((sell_price / buy_price) - 1) * 100, 2)

            else:

                rov = 0

            obj = {
                "Symbol": symbol,
                "Qty": qty,
                "Buy_Price": position_price,
                "Buy_Date": position_date,
                "Sell_Price": price,
                "Sell_Date": getDatetime(),
                "Strategy": strategy,
                "Aggregation": aggregation,
                "ROV": rov
            }

            # ADD TO CLOSED POSITIONS
            self.closed_positions.insert_one(obj)

            # REMOVE FROM OPEN POSITIONS
            self.open_positions.delete_one({
                "Symbol": symbol,
                "Strategy": strategy
            })

            # print("SELL")
            # pprint(obj)

        except Exception as e:

            print("SIM TRADER - sellOrder", e)
示例#4
0
    def updateSystemInfo(self):

        system = list(self.mongo.system.find({}))[0]

        self.mongo.system.update_one({"_id": ObjectId(system["_id"])}, {
            "$set": {
                "Threads_Running": threading.active_count(),
                "Last_Updated": getDatetime()
            }
        })
示例#5
0
    def killQueueOrder(self):
        """ METHOD QUERIES ORDERS IN QUEUE AND LOOKS AT INSERTION TIME.
            IF QUEUE ORDER INSERTION TIME GREATER THAN TWO HOURS, THEN THE ORDER IS CANCELLED.
        """
        # CHECK ALL QUEUE ORDERS AND CANCEL ORDER IF GREATER THAN TWO HOURS OLD
        queue_orders = self.queue.find({
            "Trader": self.user["Name"],
            "Asset_Type": self.asset_type,
            "Account_ID": self.account_id
        })

        dt = datetime.now(tz=pytz.UTC).replace(microsecond=0)

        dt_central = dt.astimezone(pytz.timezone('US/Central'))

        two_hours_ago = datetime.strptime(
            datetime.strftime(dt_central - timedelta(hours=2),
                              "%Y-%m-%d %H:%M:%S"), "%Y-%m-%d %H:%M:%S")

        ten_minutes_ago = datetime.strptime(
            datetime.strftime(dt_central - timedelta(minutes=10),
                              "%Y-%m-%d %H:%M:%S"), "%Y-%m-%d %H:%M:%S")

        for order in queue_orders:

            order_date = order["Date"]

            order_type = order["Order_Type"]

            id = order["Order_ID"]

            forbidden = ["REJECTED", "CANCELED", "FILLED"]

            if two_hours_ago > order_date and (
                    order_type == "BUY" or order_type == "BUY_TO_OPEN"
            ) and id != None and order["Order_Status"] not in forbidden:

                # FIRST CANCEL ORDER
                resp = self.tdameritrade.cancelOrder(id)

                if resp.status_code == 200 or resp.status_code == 201:

                    other = {
                        "Symbol": order["Symbol"],
                        "Order_Type": order["Order_Type"],
                        "Order_Status": "CANCELED",
                        "Strategy": order["Strategy"],
                        "Account_ID": self.account_id,
                        "Aggregation": order["Aggregation"],
                        "Trader": self.user["Name"],
                        "Date": getDatetime()
                    }

                    if self.asset_type == "OPTION":

                        other["Pre_Symbol"] = order["Pre_Symbol"]

                        other["Exp_Date"] = order["Exp_Date"]

                    self.other.insert_one(other)

                    self.queue.delete_one({
                        "Trader": self.user["Name"],
                        "Symbol": order["Symbol"],
                        "Strategy": order["Strategy"],
                        "Asset_Type": self.asset_type
                    })

                    self.logger.INFO(
                        f"CANCELED ORDER FOR {order['Symbol']} - TRADER: {self.user['Name']}",
                        True)

            # IF QUEUE ORDER DATE GREATER THAN 10 MINUTES OLD AND ORDER ID EQUALS NONE, SEND ALERT
            if ten_minutes_ago > order_date and order[
                    "Order_ID"] == None and order[
                        "Account_ID"] == self.account_id:

                if order["Symbol"] not in self.no_ids_list:

                    self.logger.ERROR(
                        "QUEUE ORDER ID ERROR",
                        f"ORDER ID FOR {order['Symbol']} NOT FOUND - TRADER: {self.user['Name']} - ACCOUNT ID: {self.account_id}"
                    )

                    self.no_ids_list.append(order["Symbol"])

            else:

                if order["Symbol"] in self.no_ids_list:

                    self.no_ids_list.remove(order["Symbol"])
示例#6
0
    def placeOrder(self, trade_data, position_data=None, orderType="LIMIT"):
        """ METHOD IS USED TO PLACE TRADES (BUY/SELL ORDER).

        Args:
            trade_data ([dict]): [CONSISTS OF TRADE DATA FOR EACH SYMBOL (SYMBOL, STRATEGY, AGGREGATION, ASSET TYPE, ACCOUNT ID, ORDER TYPE)]
            position_data ([dict], optional): [CONSISTS OF OPEN POSITION DATA IF SELL ORDER]. Defaults to None.
            orderType (str, optional): [EITHER A LIMIT ORDER OR MARKET ORDER]. Defaults to "LIMIT".
        """
        symbol = trade_data["Symbol"]

        side = trade_data["Side"]

        aggregation = trade_data["Aggregation"]

        strategy = trade_data["Strategy"]

        asset_type = trade_data["Asset_Type"]

        resp = self.tdameritrade.getQuote(symbol)

        if asset_type == "EQUITY":

            price = float(resp[symbol]["lastPrice"])

            if orderType == "LIMIT":

                duration = "GOOD_TILL_CANCEL"

                session = "SEAMLESS"

            else:

                duration = "DAY"

                session = "NORMAL"

            if side == "BUY":

                price = price + (price * self.limit_offset)

            elif side == "SELL":

                price = price - (price * self.limit_offset)

            if price < 1:

                price = round(price, 4)

            else:

                price = round(price, 2)

        elif asset_type == "OPTION":

            price = round(float(resp[symbol]["mark"]), 2)

            duration = "DAY"

            session = "NORMAL"

            symbol = trade_data["Pre_Symbol"]

        order = {
            "orderType":
            orderType,
            "session":
            session,
            "price":
            price,
            "duration":
            duration,
            "orderStrategyType":
            "SINGLE",
            "orderLegCollection": [{
                "instruction": side,
                "quantity": None,
                "instrument": {
                    "symbol": symbol,
                    "assetType": asset_type
                }
            }]
        }

        if orderType == "MARKET":

            del order["price"]

        obj = {
            "Symbol": symbol,
            "Qty": None,
            "Date": getDatetime(),
            "Strategy": strategy,
            "Aggregation": aggregation,
            "Trader": self.user["Name"],
            "Order_ID": None,
            "Order_Status": None,
            "Asset_Type": asset_type,
            "Order_Type": side,
            "Account_ID": self.account_id
        }

        if side == "BUY" or side == "BUY_TO_OPEN":

            # GET SHARES FOR PARTICULAR STRATEGY
            strategies = self.user["Accounts"][self.account_id]["Strategies"]

            shares = int(strategies[strategy]["Shares"])

            active_strategy = strategies[strategy]["Active"]

            if active_strategy and shares > 0:

                if asset_type == "EQUITY":

                    min_price = self.user["Accounts"][
                        self.account_id]["Price_Range"]["Min"]

                    max_price = self.user["Accounts"][
                        self.account_id]["Price_Range"]["Max"]

                    if price < min_price or price > max_price:

                        return

                order["orderLegCollection"][0]["quantity"] = shares

                obj["Limit_Price"] = price

                obj["Last_Price"] = price

                obj["Qty"] = shares

            else:

                return

        elif side == "SELL" or side == "SELL_TO_CLOSE":

            buy_qty = position_data["Qty"]

            buy_price = position_data["Buy_Price"]

            buy_date = position_data["Date"]

            order["orderLegCollection"][0]["quantity"] = buy_qty

            obj["Limit_Price"] = price

            obj["Buy_Price"] = buy_price

            obj["Buy_Date"] = buy_date

            obj["Qty"] = buy_qty

        if asset_type == "OPTION":

            obj["Pre_Symbol"] = trade_data["Pre_Symbol"]

            obj["Exp_Date"] = trade_data["Exp_Date"]

        # PLACE ORDER ################################################

        resp = self.tdameritrade.placeTDAOrder(order)

        status_code = resp.status_code

        acceptable_status = [200, 201]

        if status_code not in acceptable_status:

            other = {
                "Symbol": symbol,
                "Order_Type": side,
                "Order_Status": "REJECTED",
                "Strategy": strategy,
                "Aggregation": aggregation,
                "Trader": self.user["Name"],
                "Date": getDatetime(),
                "Asset_Type": asset_type,
                "Account_ID": self.account_id
            }

            self.logger.INFO(f"{symbol} REJECTED For {self.user['Name']}",
                             True)

            if asset_type == "OPTION":

                pprint(resp.json())

                print(resp.status_code)

                other["Pre_Symbol"] = trade_data["Pre_Symbol"]

                other["Exp_Date"] = trade_data["Exp_Date"]

            self.other.insert_one(other)

            return

        # GETS ORDER ID FROM RESPONSE HEADERS LOCATION
        obj["Order_ID"] = int(
            (resp.headers["Location"]).split("/")[-1].strip())

        obj["Order_Status"] = "QUEUED"

        self.queueOrder(obj)

        response_msg = f"{side} ORDER RESPONSE: {resp.status_code} - SYMBOL: {symbol} - TRADER: {self.user['Name']} - ASSET TYPE: {asset_type} - ACCOUNT ID: {self.account_id}"

        self.logger.INFO(response_msg)
示例#7
0
    def pushOrder(self, queue_order, spec_order):
        """ METHOD PUSHES ORDER TO EITHER OPEN POSITIONS OR CLOSED POSITIONS COLLECTION IN MONGODB.
            IF BUY ORDER, THEN PUSHES TO OPEN POSITIONS.
            IF SELL ORDER, THEN PUSHES TO CLOSED POSITIONS.

        Args:
            queue_order ([dict]): [QUEUE ORDER DATA FROM QUEUE]
            spec_order ([dict(json)]): [ORDER DATA FROM TDAMERITRADE]
        """

        symbol = queue_order["Symbol"]

        shares = int(spec_order["quantity"])

        price = spec_order["orderActivityCollection"][0]["executionLegs"][0][
            "price"]

        if price < 1:

            price = round(price, 4)

        else:

            price = round(price, 2)

        strategy = queue_order["Strategy"]

        aggregation = queue_order["Aggregation"]

        asset_type = queue_order["Asset_Type"]

        order_type = queue_order["Order_Type"]

        account_id = queue_order["Account_ID"]

        obj = {
            "Symbol": symbol,
            "Strategy": strategy,
            "Aggregation": aggregation,
            "Trader": self.user["Name"],
            "Asset_Type": asset_type,
            "Account_ID": account_id
        }

        if asset_type == "OPTION":

            obj["Pre_Symbol"] = queue_order["Pre_Symbol"]

            obj["Exp_Date"] = queue_order["Exp_Date"]

        if order_type == "BUY" or order_type == "BUY_TO_OPEN":

            obj["Qty"] = shares

            obj["Buy_Price"] = price

            obj["Last_Price"] = price

            obj["High_Price"] = price

            obj["Opening_Price"] = price

            obj["Date"] = getDatetime()

            # ADD TO OPEN POSITIONS
            try:

                self.open_positions.insert_one(obj)

            except writeConcernError:

                self.logger.ERROR(
                    f"INITIAL FAIL OF INSERTING OPEN POSITION FOR SYMBOL {symbol} - DATE/TIME: {getDatetime()} - DATA: {obj} - writeConcernError"
                )

                self.open_positions.insert_one(obj)

            except writeError:

                self.logger.ERROR(
                    f"INITIAL FAIL OF INSERTING OPEN POSITION FOR SYMBOL {symbol} - DATE/TIME: {getDatetime()} - DATA: {obj} - writeError"
                )

                self.open_positions.insert_one(obj)

            except Exception:

                self.logger.ERROR()

            msg = f"____ \n Side: {order_type} \n Symbol: {symbol} \n Qty: {shares} \n Price: ${price} \n Strategy: {strategy} \n Aggregation: {aggregation} \n Date: {getDatetime()} \n Asset Type: {asset_type} \n Trader: {self.user['Name']} \n"

            self.logger.INFO(
                f"{order_type} ORDER For {symbol} - TRADER: {self.user['Name']}",
                True)

        elif order_type == "SELL" or order_type == "SELL_TO_CLOSE":

            position = self.open_positions.find_one({
                "Trader": self.user["Name"],
                "Symbol": symbol,
                "Strategy": strategy
            })

            obj["Qty"] = position["Qty"]

            obj["Buy_Price"] = position["Buy_Price"]

            obj["Buy_Date"] = position["Date"]

            obj["Sell_Price"] = price

            obj["Sell_Date"] = getDatetime()

            obj["High_Price"] = position["High_Price"]

            sell_price = round(price * position["Qty"], 2)

            buy_price = round(position["Buy_Price"] * position["Qty"], 2)

            if buy_price != 0:

                rov = round(((sell_price / buy_price) - 1) * 100, 2)

            else:

                rov = 0

            if rov > 0 or sell_price - buy_price > 0:

                sold_for = "GAIN"

            elif rov < 0 or sell_price - buy_price < 0:

                sold_for = "LOSS"

            else:

                sold_for = "NONE"

            obj["ROV"] = rov

            msg = f"____ \n Side: {order_type} \n Symbol: {symbol} \n Qty: {position['Qty']} \n Buy Price: ${position['Buy_Price']} \n Buy Date: {position['Date']} \n Sell Price: ${price} \n Sell Date: {getDatetime()} \n Strategy: {strategy} \n Aggregation: {aggregation} \n ROV: {rov}% \n Sold For: {sold_for} \n Asset Type: {asset_type} \n Trader: {self.user['Name']} \n"

            # ADD TO CLOSED POSITIONS
            try:

                self.closed_positions.insert_one(obj)

            except writeConcernError:

                self.logger.ERROR(
                    f"INITIAL FAIL OF INSERTING CLOSED POSITION FOR SYMBOL {symbol} - DATE/TIME: {getDatetime()} - DATA: {obj} - writeConcernError"
                )

                self.closed_positions.insert_one(obj)

            except writeError:

                self.logger.ERROR(
                    f"INITIAL FAIL OF INSERTING CLOSED POSITION FOR SYMBOL {symbol} - DATE/TIME: {getDatetime()} - DATA: {obj} - writeError"
                )

                self.closed_positions.insert_one(obj)

            except Exception:

                self.logger.ERROR()

            # REMOVE FROM OPEN POSITIONS
            is_removed = self.open_positions.delete_one({
                "Trader":
                self.user["Name"],
                "Symbol":
                symbol,
                "Strategy":
                strategy,
                "Asset_Type":
                self.asset_type
            })

            try:

                if int(is_removed.deleted_count) == 0:

                    self.logger.ERROR(
                        f"INITIAL FAIL OF DELETING OPEN POSITION FOR SYMBOL {symbol} - DATE/TIME: {getDatetime()} - DATA: {obj}"
                    )

                    self.open_positions.delete_one({
                        "Trader":
                        self.user["Name"],
                        "Symbol":
                        symbol,
                        "Strategy":
                        strategy,
                        "Asset_Type":
                        self.asset_type
                    })

            except Exception:

                self.logger.ERROR()

            self.logger.INFO(
                f"{order_type} ORDER For {symbol} - TRADER: {self.user['Name']}",
                True)

        # REMOVE FROM QUEUE
        self.queue.delete_one({
            "Trader": self.user["Name"],
            "Symbol": symbol,
            "Strategy": strategy,
            "Asset_Type": asset_type,
            "Account_ID": self.account_id
        })

        self.push.send(msg)
示例#8
0
    def updateStatus(self):
        """ METHOD QUERIES THE QUEUED ORDERS AND USES THE ORDER ID TO QUERY TDAMERITRADES ORDERS FOR ACCOUNT TO CHECK THE ORDERS CURRENT STATUS.
            INITIALLY WHEN ORDER IS PLACED, THE ORDER STATUS ON TDAMERITRADES END IS SET TO WORKING OR QUEUED. THREE OUTCOMES THAT I AM LOOKING FOR ARE
            FILLED, CANCELED, REJECTED.

            IF FILLED, THEN QUEUED ORDER IS REMOVED FROM QUEUE AND THE pushOrder METHOD IS CALLED.

            IF REJECTED OR CANCELED, THEN QUEUED ORDER IS REMOVED FROM QUEUE AND SENT TO OTHER COLLECTION IN MONGODB.
        """
        queued_orders = self.queue.find({
            "Trader": self.user["Name"],
            "Order_ID": {
                "$ne": None
            },
            "Asset_Type": self.asset_type,
            "Account_ID": self.account_id
        })

        for queue_order in queued_orders:

            spec_order = self.tdameritrade.getSpecificOrder(
                queue_order["Order_ID"])

            new_status = spec_order["status"]

            order_type = queue_order["Order_Type"]

            # CHECK IF QUEUE ORDER ID EQUALS TDA ORDER ID
            if queue_order["Order_ID"] == spec_order["orderId"]:

                if new_status == "FILLED":

                    self.pushOrder(queue_order, spec_order)

                elif new_status == "CANCELED" or new_status == "REJECTED":

                    # REMOVE FROM QUEUE
                    self.queue.delete_one({
                        "Trader": self.user["Name"],
                        "Symbol": queue_order["Symbol"],
                        "Strategy": queue_order["Strategy"],
                        "Asset_Type": self.asset_type,
                        "Account_ID": self.account_id
                    })

                    other = {
                        "Symbol": queue_order["Symbol"],
                        "Order_Type": order_type,
                        "Order_Status": new_status,
                        "Strategy": queue_order["Strategy"],
                        "Aggregation": queue_order["Aggregation"],
                        "Trader": self.user["Name"],
                        "Date": getDatetime(),
                        "Asset_Type": queue_order["Asset_Type"],
                        "Account_ID": self.account_id
                    }

                    if self.asset_type == "OPTION":

                        other["Pre_Symbol"] = queue_order["Pre_Symbol"]

                        other["Exp_Date"] = queue_order["Exp_Date"]

                    self.other.insert_one(other)

                    self.logger.INFO(
                        f"{new_status.upper()} ORDER For {queue_order['Symbol']} - TRADER: {self.user['Name']}",
                        True)

                else:

                    self.queue.update_one(
                        {
                            "Trader": self.user["Name"],
                            "Symbol": queue_order["Symbol"],
                            "Strategy": queue_order["Strategy"],
                            "Asset_Type": self.asset_type
                        }, {"$set": {
                            "Order_Status": new_status
                        }})
示例#9
0
        tm = dt_central.strftime("%H:%M:%S")

        weekdays = ["Sat", "Sun"]

        # IF CURRENT TIME GREATER THAN 8PM AND LESS THAN 4AM, OR DAY IS WEEKEND, THEN RETURN 60 SECONDS
        if tm > "20:00" or tm < "04:00" or day in weekdays:

            return 60

        # ELSE RETURN 5 SECONDS
        return 5

    main = Main()

    # UPDATE SYSTEM RUN DATETIME FIELD TO CURRENT DATETIME
    # THIS TELLS US WHEN THE SYSTEM FIRST STARTED UP
    system = list(main.mongo.system.find({}))[0]

    main.mongo.system.update_one({"_id": ObjectId(system["_id"])},
                                 {"$set": {
                                     "Run_Start": getDatetime()
                                 }})

    while True:

        main.run()

        main.updateSystemInfo()

        time.sleep(selectSleep())
示例#10
0
        day = dt_central.strftime("%a")

        tm = dt_central.strftime("%H:%M:%S")

        weekdays = ["Sat", "Sun"]

        # IF CURRENT TIME GREATER THAN 8PM AND LESS THAN 4AM, OR DAY IS WEEKEND, THEN RETURN 60 SECONDS
        if tm > "20:00" or tm < "04:00" or day in weekdays:

            return 60

        # ELSE RETURN 5 SECONDS
        return 5

    main = Main()

    # UPDATE SYSTEM RUN DATETIME FIELD TO CURRENT DATETIME
    # THIS TELLS US WHEN THE SYSTEM FIRST STARTED UP
    system = list(main.mongo.system.find({}))[0]

    main.mongo.system.update_one({"_id": ObjectId(system["_id"])}, {
                                 "$set": {"Run_Start": getDatetime()}})
    
    while True:

        main.run()

        main.updateSystemInfo()
        
        time.sleep(selectSleep())