Пример #1
0
async def green_light(pilot_name: str, passenger: AutoPilotTask,
                      etrade: AsyncEtrade) -> bool:
    # handle override signal
    if passenger.signal == AutoPilotTask.MANUAL_OVERRIDE:
        logger.info("%s %s received signal MANUAL_OVERRIDE.", PREFIX,
                    pilot_name)
        logger.info("%s %s releasing control...", PREFIX, pilot_name)
        passenger.status = AutoPilotTask.DONE
        return False

    # if no market session, sleep until market opens
    if MarketSession.current(passenger.is_otc) is None:
        logger.debug("%s %s market is closed. sleeping 1h", PREFIX, pilot_name)
        time_till_open = time_till_market_open(passenger.is_otc)
        await asyncio.sleep(time_till_open)
        return False

    # if no access token, sleep 1s (repeat until valid access)
    if not etrade.is_session_active():
        logger.debug("%s %s waiting for valid %s session...", PREFIX,
                     pilot_name, etrade.name)
        await asyncio.sleep(1)
        return False

    return True
Пример #2
0
async def sell_position(pilot_name: str, passenger: AutoPilotTask,
                        etrade: AsyncEtrade):
    if not passenger.tracking_order_id:
        quote = await etrade.get_quote(passenger.symbol)
        ask = get_ask(quote)
        await commit_sell(passenger, ask, etrade)
        return

    order = await etrade.get_order_details(passenger.account.account_key,
                                           passenger.tracking_order_id,
                                           passenger.symbol)
    if not order:
        logger.info("%s %s unable to track sell order %s. NOT FOUND.", PREFIX,
                    pilot_name, passenger.tracking_order_id)

        passenger.status = AutoPilotTask.PAUSED
        passenger.state = AutoPilotTask.ERROR
        passenger.error_message = f'unable to track selling order {passenger.tracking_order_id}. NOT FOUND'
        return

    details = order.get("OrderDetail")[0]
    status = OrderStatus(details.get("status"))
    limit_price = details.get("limitPrice")

    if status in (OrderStatus.OPEN, OrderStatus.PARTIAL):
        quote = await etrade.get_quote(passenger.symbol)
        bid = get_bid(quote)
        ask = get_ask(quote)
        placed_at = datetime.utcfromtimestamp(
            details.get("placedTime") / 1000).replace(tzinfo=pytz.utc)
        elapsed_time = timezone.now() - placed_at
        if elapsed_time >= timedelta(seconds=5) and (limit_price < bid
                                                     or limit_price > ask):
            try:
                await etrade.cancel_order(passenger.account.account_key,
                                          passenger.tracking_order_id)
            except ServiceError as e:
                if e.error_code == 5001:
                    # This order is currently being executed
                    # or rejected. It cannot be cancelled.
                    return

    elif status == OrderStatus.CANCEL_REQUESTED:
        logger.debug(
            "%s %s cancel for order %s has been requested. waiting...", PREFIX,
            pilot_name, passenger.tracking_order_id)

    elif status == OrderStatus.CANCELLED:
        logger.debug("%s %s order %s cancelled. placing new sell order...",
                     PREFIX, pilot_name, passenger.tracking_order_id)
        instrument = details.get("Instrument")[0]
        ordered_quantity = instrument.get("orderedQuantity")
        filled_quantity = instrument.get("filledQuantity") or 0
        pending_quantity = int(ordered_quantity) - int(filled_quantity)
        passenger.quantity = pending_quantity

        quote = await etrade.get_quote(passenger.symbol)
        ask = get_ask(quote)
        await commit_sell(passenger, ask, etrade)

    elif status == OrderStatus.REJECTED:
        logger.warning(
            "%s %s order %s rejected. this case is not being handled.", PREFIX,
            pilot_name, passenger.tracking_order_id)

    elif status == OrderStatus.EXPIRED:
        logger.warning(
            "%s %s order %s expired. this case is not being handled.", PREFIX,
            pilot_name, passenger.tracking_order_id)

    elif status == OrderStatus.EXECUTED:
        # get possition
        quantity = await etrade.get_position_quantity(
            passenger.account.account_key, passenger.symbol)
        if quantity in (None, 0):
            instrument = details.get("Instrument")[0]
            avg_execution_price = Decimal(
                instrument.get("averageExecutionPrice"))
            passenger.status = AutoPilotTask.DONE
            passenger.exit_price = avg_execution_price

            percent = passenger.exit_percent
            percent_label = "profit" if percent > Decimal(0) else "loss"
            logger.info("%s %s position sold for a %s%% %s", PREFIX,
                        pilot_name, percent, percent_label)
            if passenger.discord_webhook:
                await post_webhook(
                    passenger.discord_webhook,
                    f"{passenger.symbol} position sold for a {percent}% {percent_label}"
                )
        else:
            # TODO: place sell order for scale out quantity
            passenger.quantity = quantity

            quote = await etrade.get_quote(passenger.symbol)
            ask = get_ask(quote)
            await commit_sell(passenger, ask, etrade)
    else:
        logger.error("%s %s unhandled status %s for order %s", PREFIX,
                     pilot_name, status, passenger.tracking_order_id)
        passenger.status = AutoPilotTask.PAUSED
        passenger.state = AutoPilotTask.ERROR
        passenger.error_message = f'unhandled status {status} for order {passenger.tracking_order_id}'