"""The sample demonstrates how to get options-related instrument properties in new mode"""

import logging
import threading

from tabulate import tabulate
from win32com.client import Dispatch, constants

import CELEnvironment
from CELEnvironment import AssertMessage

#region Settings

# Replace it with enabled symbol
SYMBOL = "C.EP"

# Logging settings: specify log level and log format here.
# Set log level to DEBUG to see more internal messages.
# See more information about logging lib usage: https://docs.python.org/3/howto/logging-cookbook.html

CELEnvironment.LOG_LEVEL = logging.INFO
# CELEnvironment.LOG_FORMAT = ...

# CELEnvironment.SinkInternal uses own LOG_LEVEL (which is inherited from the global one) and own LOG_FORMAT.
# You can redefine them as follows:
# CELEnvironment.SinkInternal.LOG_LEVEL = logging.DEBUG
# CELEnvironment.SinkInternal.LOG_FORMAT = ...

LOG = CELEnvironment.GetLogger()

#endregion

OPTIONS_PROPS = [
    constants.ipNetChange,
    constants.ipDelta,
    constants.ipDeltaNetChange,
    constants.ipTheta,
    constants.ipThetaNetChange,
    constants.ipGamma,
    constants.ipGammaNetChange,
    constants.ipVega,
    constants.ipVegaNetChange,
    constants.ipRho,
    constants.ipRhoNetChange,
    constants.ipAverageVolatility,
    constants.ipImpliedVolatility,
    constants.ipImpliedVolatilityOnAsk,
    constants.ipImpliedVolatilityOnBid,
    constants.ipImpliedVolatilityNetChange,
    constants.ipVolatilityCurve,
    constants.ipTheoreticalValue,
    constants.ipTheoValueNetChange
]
"""List of option Greeks and volatility properties enum values.
"""


def _printGreeks(cqgInstrument):
    instrument = Dispatch(cqgInstrument)
    properties = instrument.Properties
    table = []
    for propEnum in OPTIONS_PROPS:
        prop = properties(propEnum)
        assert prop is not None  # NOTE: it is None for non-options contracts
        table.append([prop.Name, prop.Value])

    LOG.info("Greeks and volatility properties:\n%s", tabulate(table))


class OptionsData(CELEnvironment.CELSinkBase):
    def __init__(self):
        self.eventDone = threading.Event()

    def Init(self, celEnvironment):
        self.celEnvironment = celEnvironment

    def Start(self):
        LOG.info("Request instrument properties for %s", SYMBOL)
        request = self.celEnvironment.cqgCEL.CreateInstrumentRequest()
        request.Symbol = SYMBOL
        request.QuoteLevel = constants.qsNone
        request.DOMStatus = False
        request.PropertyLevel = constants.psNetChange | constants.psGreeks | constants.psVolatility |\
            constants.psTheoreticalValue

        self.celEnvironment.cqgCEL.SubscribeNewInstrument(request)
        AssertMessage(self.eventDone.wait(10), "Failed to wait for the contract resolution")

        input("Waiting for the option values update, press Enter to exit...\n")

    def OnDataError(self, cqgError, errorDescription):
        if cqgError is not None:
            error = Dispatch(cqgError)
            LOG.error("OnDataError: Code: %d Description: %s", error.Code, error.Description)

        self.eventDone.set()

    def OnInstrumentResolved(self, symbol, cqgInstrument, cqgError):
        if cqgError is not None:
            error = Dispatch(cqgError)
            LOG.error("OnInstrumentResolved error: Error code: %d Description: %s", error.Code, error.Description)
            self.eventDone.set()
            return

        _printGreeks(cqgInstrument)
        self.eventDone.set()

    def OnInstrumentChanged(self, cqgInstrument, cqgQuotes, cqgInstrumentProperties):
        _printGreeks(cqgInstrument)
        print("Waiting for the option values update, press Enter to exit...")


# If CQGCEL.APIConfiguration must be customized then do it in this function
def CustomAPIConfiguration(APIConfiguration):
    # http://partners.cqg.com/sites/default/files/docs/CQGAPI_4.0R/webframe.html#CQG~CQGAPIConfig~NewInstrumentMode.html
    APIConfiguration.NewInstrumentMode = True


if __name__ == "__main__":
    CELEnvironment.Start(OptionsData, CustomAPIConfiguration)
