"""The sample makes a Constant Volume Bar (CVB) request and waits for response and updates for 20 sec
"""

import logging
import threading
import win32com.client
import CELEnvironment

#region Settings

SYMBOL = "DD"           # Replace it with enabled symbol
VOLUME_LEVEL = 100.50   # Replace with desired volume level, supports both integer and fractional values

# 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


class ConstantVolumeBarsSample(CELEnvironment.CELSinkBase):
    def __init__(self):
        self.eventDone = threading.Event()

    def Init(self, celEnvironment):
        self.celEnvironment = celEnvironment

    def Start(self):
        request = win32com.client.Dispatch(self.celEnvironment.cqgCEL.CreateConstantVolumeBarsRequest())
        request.Symbol = SYMBOL
        request.RangeStart = 0
        request.RangeEnd = -10
        request.VolumeLevelFractional = VOLUME_LEVEL
        request.VolumeType = win32com.client.constants.cvbvtActual
        request.Continuation = win32com.client.constants.tsctStandard
        request.SubscriptionLevel = win32com.client.constants.tslEachTick
        request.UpdatesEnabled = True

        self.celEnvironment.cqgCEL.RequestConstantVolumeBars(request)

        self.eventDone.wait(20)

    def OnDataError(self, cqgError, errorDescription):
        if cqgError is not None:
            error = win32com.client.Dispatch(cqgError)
            LOG.error("OnDataError: Code: %d Description: %s", error.Code, error.Description)

        self.eventDone.set()

    def OnConstantVolumeBarsResolved(self, cqgConstantVolumeBars, cqgError):
        if cqgError is not None:
            error = win32com.client.Dispatch(cqgError)
            LOG.error(
                "OnConstantVolumeBarsResolved: Code: %d Description: %s", error.Code, error.Description)
            self.eventDone.set()
        else:
            bars = win32com.client.Dispatch(cqgConstantVolumeBars)
            LOG.info("OnConstantVolumeBarsResolved: Bars count: %d Bars:", bars.Count)
            for i in range(0, bars.Count):
                self.dumpBar(win32com.client.Dispatch(bars.Item(i)), i)

    def OnConstantVolumeBarsAdded(self, cqgConstantVolumeBars):
        bars = win32com.client.Dispatch(cqgConstantVolumeBars)
        LOG.info("OnConstantVolumeBarsAdded: Bars count: %d Bars:", bars.Count)
        for i in range(0, bars.Count):
            self.dumpBar(win32com.client.Dispatch(bars.Item(i)), i)

    def OnConstantVolumeBarsUpdated(self, cqgConstantVolumeBars, index):
        LOG.info("OnConstantVolumeBarsUpdated: Updated bar index %d", index)
        bars = win32com.client.Dispatch(cqgConstantVolumeBars)
        self.dumpBar(win32com.client.Dispatch(bars.Item(index)), index)

    def dumpBar(self, bar, index):
        LOG.info(
            "   Bar index: %d Timestamp %s Open %f High %f Low %f Close %f "
            "ActualVolumeFractional %s AskVolumeFractional %s BidVolumeFractional %s TickVolume %d",
            index,
            bar.Timestamp,
            bar.Open,
            bar.High,
            bar.Low,
            bar.Close,
            bar.ActualVolumeFractional,
            bar.AskVolumeFractional,
            bar.BidVolumeFractional,
            bar.TickVolume
        )


if __name__ == "__main__":
    CELEnvironment.Start(ConstantVolumeBarsSample)
