StatArb / StatBot / Execution / func_trade_management.py
func_trade_management.py
Raw
from logging import exception
from config_execution_api import signal_positive_ticker
from config_execution_api import signal_negative_ticker
from config_execution_api import signal_trigger_thresh
from config_execution_api import tradeable_capital_usdt
from config_execution_api import limit_order_basis
from config_execution_api import session_private
from config_execution_api import volatility_check
from config_execution_api import hedge_ratio
from func_price_calls import get_ticker_trade_liquidity
from func_get_zscore import get_latest_zscore
from func_execution_calls import initialise_order_execution
from func_order_review import check_order
from func_position_calls import query_existing_order
from func_check_volatility import check_volatility

import time
from exceptions import FailedRequestError, InvalidRequestError
from requests.exceptions import ConnectionError, Timeout, RequestException
from json.decoder import JSONDecodeError

# Manage new trade assessment and order placing
def manage_new_trades(kill_switch):

    # Set variables
    order_long_id = ""
    order_short_id = ""
    signal_side = ""
    low_volatility = True
    hot = False
    zscore_entry = 0

    exception = False
    order_long_qty = 0
    order_long_time = ""
    order_short_qty = 0
    order_short_time = ""
    order_long_price = 0
    order_short_price = 0

    # Get and save the latest z-score
    zscore, signal_sign_positive, exception = get_latest_zscore()
    print(zscore, signal_sign_positive, exception)
    
    if exception:
        return (0, "", 0, "", 0, 0, "", 0, 0, exception)

    # Switch to hot if meets signal threshold
    # Note: You can add in coint-flag check too if you want extra vigilence
    if volatility_check:
        low_volatility = not any ([check_volatility(signal_positive_ticker), check_volatility(signal_negative_ticker)])
    
    if low_volatility:
        print("Low Volatile Market - Ready for Entry")

    if abs(zscore) > signal_trigger_thresh:

        # Active hot trigger
        hot = True
        zscore_entry = zscore
        print("-- Trade Status HOT --")
        print("-- Placing and Monitoring Existing Trades --")

    # Place and manage trades
    if hot and kill_switch == 0 and low_volatility:

        # Get trades history for liquidity
        avg_liquidity_ticker_p, last_price_p, exception = get_ticker_trade_liquidity(signal_positive_ticker)
        if exception:
            return (0, "", 0, "", 0, 0, "", 0, 0, exception)
        avg_liquidity_ticker_n, last_price_n, exception = get_ticker_trade_liquidity(signal_negative_ticker)
        if exception:
            return (0, "", 0, "", 0, 0, "", 0, 0, exception)

        # Determine long ticker vs short ticker
        if signal_sign_positive:
            long_ticker = signal_positive_ticker
            short_ticker = signal_negative_ticker
            avg_liquidity_long = avg_liquidity_ticker_p
            avg_liquidity_short = avg_liquidity_ticker_n
            last_price_long = last_price_p
            last_price_short = last_price_n
            # capital_long = tradeable_capital_usdt * 0.5      # Newly added for calculating hedged quantity
            # capital_short = capital_long * hedge_ratio       # Spread = Short ticker - hedge ratio * Long ticker
        else:
            long_ticker = signal_negative_ticker
            short_ticker = signal_positive_ticker
            avg_liquidity_long = avg_liquidity_ticker_n
            avg_liquidity_short = avg_liquidity_ticker_p
            last_price_long = last_price_n
            last_price_short = last_price_p
            # capital_short = tradeable_capital_usdt * 0.5     # Newly added for calculating hedged quantity
            # capital_long = capital_short * hedge_ratio       # Spread = hedge ratio * Short ticker - Long ticker 

        # Fill targets
        capital_long = tradeable_capital_usdt * 0.5                              # <- Original Code Fully hedge
        capital_short = tradeable_capital_usdt - capital_long                    # <- Original Code Fully hedge
        initial_fill_target_long_usdt = avg_liquidity_long * last_price_long
        initial_fill_target_short_usdt = avg_liquidity_short * last_price_short
        initial_capital_injection_usdt = min(initial_fill_target_long_usdt, initial_fill_target_short_usdt)

        # Ensure initial cpaital does not exceed limits set in configuration
        if limit_order_basis:
            if initial_capital_injection_usdt > capital_long:
                initial_capital_usdt = capital_long
            else:
                initial_capital_usdt = initial_capital_injection_usdt
        else:
            initial_capital_usdt = capital_long

        # Set remaining capital
        remaining_capital_long = capital_long
        remaining_capital_short = capital_short

        # Trade until filled or signal is false
        order_status_long = ""
        order_status_short = ""
        counts_long = 0
        counts_short = 0
        while kill_switch == 0:

            # Place order - long
            if counts_long == 0:
                order_long_id,order_long_time,order_long_qty,exception = initialise_order_execution(long_ticker, "Long", initial_capital_usdt)       #<- Original Code Fully hedge
                # order_long_id,order_long_time,order_long_qty,exception = initialise_order_execution(long_ticker, "Long", capital_long)
                print(f"Long Ticker: {long_ticker}; Long Order ID: {order_long_id}; Long Order time: {order_long_time}; Long Order qty: {order_long_qty}; Exception: {exception}")
                if exception:
                    continue
                order_long_price,_,_ = query_existing_order(long_ticker, order_long_id,"")
                counts_long = 1 if order_long_id else 0
                remaining_capital_long = remaining_capital_long - initial_capital_usdt

            # Place order - short
            if counts_short == 0:
                order_short_id,order_short_time,order_short_qty,exception = initialise_order_execution(short_ticker, "Short", initial_capital_usdt)  #<- Original Code Fully hedge
                # order_short_id,order_short_time,order_short_qty,exception = initialise_order_execution(short_ticker, "Short", capital_short)
                print(f"Short Ticker: {short_ticker}; Short Order ID: {order_short_id}; Short Order time: {order_short_time}; Short Order qty: {order_short_qty}; Exception: {exception}")
                if exception:
                    continue
                order_short_price,_,_ = query_existing_order(short_ticker, order_short_id,"")
                counts_short = 1 if order_short_id else 0
                remaining_capital_short = remaining_capital_short - initial_capital_usdt

            # Update signal side
            if zscore > 0:
                signal_side = "positive"
            else:
                signal_side = "negative"

            # Handle kill switch for Market orders
            if not limit_order_basis and counts_long and counts_short:
                kill_switch = 1

            # Allow for time to register the limit orders
            time.sleep(3)

            # Check limit orders and ensure z_score is still within range
            zscore_new, signal_sign_p_new, exception = get_latest_zscore()
            if exception:
                continue
            if kill_switch == 0:
                if abs(zscore_new) > signal_trigger_thresh * 0.9 and signal_sign_p_new == signal_sign_positive:

                    # Check long order status
                    if counts_long == 1:
                        order_status_long, exception = check_order(long_ticker, order_long_id, remaining_capital_long, "Long")
                    if exception:
                        continue
                    # Check short order status
                    if counts_short == 1:
                        order_status_short, exception = check_order(short_ticker, order_short_id, remaining_capital_short, "Short")
                    if exception:
                        continue
                    print(order_status_long, order_status_short, round(zscore_new,2))

                    # If orders still active, do nothing
                    if order_status_long == "Order Active" or order_status_short == "Order Active":
                        continue

                    # If orders partial fill, do nothing
                    if order_status_long == "Partial Fill" or order_status_short == "Partial Fill":
                        continue

                    # If orders trade complete, do nothing - stop opening trades
                    if order_status_long == "Trade Complete" and order_status_short == "Trade Complete":
                        kill_switch = 1

                    # If position filled - place another trade
                    if order_status_long == "Position Filled" and order_status_short == "Position Filled":
                        counts_long = 0
                        counts_short = 0

                    # If order cancelled for long - try again
                    if order_status_long == "Try Again":
                        counts_long = 0

                    # If order cancelled for short - try again
                    if order_status_short == "Try Again":
                        counts_short = 0

                else:
                    # Cancel all active orders
                    try:
                        print("\n")
                        print('-------------------------------------------------------------------')
                        print("Fund Trade Mgmt") 
                        print(session_private.cancel_all_active_orders(symbol=signal_positive_ticker))
                        print(session_private.cancel_all_active_orders(symbol=signal_negative_ticker))
                        print('-------------------------------------------------------------------')
                        print("\n")

                        kill_switch = 1
                    except (ConnectionError, Timeout, RequestException, JSONDecodeError, FailedRequestError, InvalidRequestError) as e:
                        print(e)
                        continue
            if limit_order_basis:
                zscore_entry = zscore_new
    # Output status
    # print(kill_switch, signal_side, order_long_qty, order_long_time, order_long_price, order_short_qty, order_short_time, order_short_price, exception)
    return (kill_switch, signal_side, order_long_qty, order_long_time, order_long_price, order_short_qty, order_short_time, order_short_price, zscore_entry, exception)