import datetime

import QuantConnect
import QuantConnect.Algorithm.Framework.Alphas
import QuantConnect.Algorithm.Framework.Alphas.Analysis
import QuantConnect.Interfaces
import QuantConnect.Lean.Engine.Alpha
import QuantConnect.Lean.Engine.Alphas
import QuantConnect.Lean.Engine.TransactionHandlers
import QuantConnect.Packets
import System
import System.Threading


class StatisticsInsightManagerExtension(System.Object, QuantConnect.Algorithm.Framework.Alphas.IInsightManagerExtension):
    """Manages alpha statistics responsbilities"""

    @property
    def Statistics(self) -> QuantConnect.AlphaRuntimeStatistics:
        """
        Gets the current statistics. The values are current as of the time specified
        in AlphaRuntimeStatistics.MeanPopulationScore and AlphaRuntimeStatistics.RollingAveragedPopulationScore
        """
        ...

    @property
    def RollingAverageIsReady(self) -> bool:
        """Gets whether or not the rolling average statistics is ready"""
        ...

    def __init__(self, accountCurrencyProvider: QuantConnect.Interfaces.IAccountCurrencyProvider, tradablePercentOfVolume: float = 0.01, period: int = 100, requireRollingAverageWarmup: bool = False) -> None:
        """
        Initializes a new instance of the StatisticsInsightManagerExtension class
        
        :param accountCurrencyProvider: The account currency provider
        :param tradablePercentOfVolume: Percent of volume of first bar used to estimate the maximum number of tradable shares. Defaults to 1%
        :param period: The period used for exponential smoothing of scores - this is a number of insights. Defaults to 100 insight predictions.
        :param requireRollingAverageWarmup: Specify true to force the population average scoring to warmup before plotting.
        """
        ...

    def OnInsightGenerated(self, context: QuantConnect.Algorithm.Framework.Alphas.Analysis.InsightAnalysisContext) -> None:
        """
        Handles the IAlgorithm.InsightsGenerated event
        Increments total, long and short counters. Updates long/short ratio
        
        :param context: The newly generated insight context
        """
        ...

    def OnInsightClosed(self, context: QuantConnect.Algorithm.Framework.Alphas.Analysis.InsightAnalysisContext) -> None:
        """
        Computes an estimated value for the insight. This is intended to be invoked at the end of the
        insight period, i.e, when now == insight.GeneratedTimeUtc + insight.Period;
        
        :param context: Context whose insight has just closed
        """
        ...

    def OnInsightAnalysisCompleted(self, context: QuantConnect.Algorithm.Framework.Alphas.Analysis.InsightAnalysisContext) -> None:
        """
        Updates the specified statistics with the new scores
        
        :param context: Context whose insight has just completed analysis
        """
        ...

    def Step(self, frontierTimeUtc: datetime.datetime) -> None:
        """
        Invokes the manager at the end of the time step.
        
        :param frontierTimeUtc: The current frontier time utc
        """
        ...

    def InitializeForRange(self, algorithmStartDate: datetime.datetime, algorithmEndDate: datetime.datetime, algorithmUtcTime: datetime.datetime) -> None:
        """
        Allows the extension to initialize itself over the expected range
        
        :param algorithmStartDate: The start date of the algorithm
        :param algorithmEndDate: The end date of the algorithm
        :param algorithmUtcTime: The algorithm's current utc time
        """
        ...


class ChartingInsightManagerExtension(System.Object, QuantConnect.Algorithm.Framework.Alphas.IInsightManagerExtension):
    """Manages alpha charting responsibilities."""

    AlphaAssets: str = "Alpha Assets"
    """The string name used for the Alpha Assets chart"""

    @property
    def SampleInterval(self) -> datetime.timedelta:
        """
        Gets or sets the interval at which alpha charts are updated. This is in realtion to algorithm time.
        
        This property is protected.
        """
        ...

    @SampleInterval.setter
    def SampleInterval(self, value: datetime.timedelta):
        """
        Gets or sets the interval at which alpha charts are updated. This is in realtion to algorithm time.
        
        This property is protected.
        """
        ...

    def __init__(self, algorithm: QuantConnect.Interfaces.IAlgorithm, statisticsManager: QuantConnect.Lean.Engine.Alphas.StatisticsInsightManagerExtension) -> None:
        """
        Initializes a new instance of the ChartingInsightManagerExtension class
        
        :param algorithm: The algorithm instance. This is only used for adding the charts to the algorithm. We purposefully do not save a reference to avoid potentially inconsistent reads
        :param statisticsManager: Statistics manager used to access mean population scores for charting
        """
        ...

    def Step(self, frontierTimeUtc: datetime.datetime) -> None:
        """
        Invokes the manager at the end of the time step.
        Samples and plots insight counts and population score.
        
        :param frontierTimeUtc: The current frontier time utc
        """
        ...

    def InitializeForRange(self, algorithmStartDate: datetime.datetime, algorithmEndDate: datetime.datetime, algorithmUtcTime: datetime.datetime) -> None:
        """
        Invoked after IAlgorithm.Initialize has been called.
        Determines chart sample interval and initial sample times
        
        :param algorithmStartDate: The start date of the algorithm
        :param algorithmEndDate: The end date of the algorithm
        :param algorithmUtcTime: The algorithm's current utc time
        """
        ...

    def OnInsightGenerated(self, context: QuantConnect.Algorithm.Framework.Alphas.Analysis.InsightAnalysisContext) -> None:
        """
        Handles the IAlgorithm.InsightsGenerated event.
        Keep daily and total count of insights by symbol
        
        :param context: The newly generated insight analysis context
        """
        ...

    def OnInsightClosed(self, context: QuantConnect.Algorithm.Framework.Alphas.Analysis.InsightAnalysisContext) -> None:
        """
        NOP - Charting is more concerned with population vs individual insights
        
        :param context: Context whose insight has just completed analysis
        """
        ...

    def OnInsightAnalysisCompleted(self, context: QuantConnect.Algorithm.Framework.Alphas.Analysis.InsightAnalysisContext) -> None:
        """
        NOP - Charting is more concerned with population vs individual insights
        
        :param context: Context whose insight has just completed analysis
        """
        ...


class DefaultAlphaHandler(System.Object, QuantConnect.Lean.Engine.Alpha.IAlphaHandler):
    """Default alpha handler that supports sending insights to the messaging handler, analyzing insights online"""

    class AlphaResultPacketSender(System.Object, QuantConnect.Algorithm.Framework.Alphas.IInsightManagerExtension, System.IDisposable):
        """
        Encapsulates routing finalized insights to the messaging handler
        
        This class is protected.
        """

        def __init__(self, job: QuantConnect.Packets.AlgorithmNodePacket, messagingHandler: QuantConnect.Interfaces.IMessagingHandler, interval: datetime.timedelta, maximumNumberOfInsightsPerPacket: int) -> None:
            """
            Initialize a new instance of AlphaResultPacketSender
            
            :param job: Algorithm job
            :param messagingHandler: Message handler to use
            :param interval: Timespan interval
            :param maximumNumberOfInsightsPerPacket: Limit on insights per packet
            """
            ...

        def OnInsightAnalysisCompleted(self, context: QuantConnect.Algorithm.Framework.Alphas.Analysis.InsightAnalysisContext) -> None:
            """Enqueue finalized insights to be sent via the messaging handler"""
            ...

        def Step(self, frontierTimeUtc: datetime.datetime) -> None:
            """No operation"""
            ...

        def InitializeForRange(self, algorithmStartDate: datetime.datetime, algorithmEndDate: datetime.datetime, algorithmUtcTime: datetime.datetime) -> None:
            """No operation"""
            ...

        def OnInsightGenerated(self, context: QuantConnect.Algorithm.Framework.Alphas.Analysis.InsightAnalysisContext) -> None:
            """No operation"""
            ...

        def OnInsightClosed(self, context: QuantConnect.Algorithm.Framework.Alphas.Analysis.InsightAnalysisContext) -> None:
            """No operation"""
            ...

        def Dispose(self) -> None:
            """Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources."""
            ...

    @property
    def CancellationToken(self) -> System.Threading.CancellationToken:
        """
        The cancellation token that will be cancelled when requested to exit
        
        This property is protected.
        """
        ...

    @property
    def IsActive(self) -> bool:
        """Gets a flag indicating if this handler's thread is still running and processing messages"""
        ...

    @IsActive.setter
    def IsActive(self, value: bool):
        """Gets a flag indicating if this handler's thread is still running and processing messages"""
        ...

    @property
    def RuntimeStatistics(self) -> QuantConnect.AlphaRuntimeStatistics:
        """Gets the current alpha runtime statistics"""
        ...

    @RuntimeStatistics.setter
    def RuntimeStatistics(self, value: QuantConnect.AlphaRuntimeStatistics):
        """Gets the current alpha runtime statistics"""
        ...

    @property
    def AlgorithmId(self) -> str:
        """
        Gets the algorithm's unique identifier
        
        This property is protected.
        """
        ...

    @property
    def LiveMode(self) -> bool:
        """
        Gets whether or not the job is a live job
        
        This property is protected.
        """
        ...

    @property
    def Job(self) -> QuantConnect.Packets.AlgorithmNodePacket:
        """
        Gets the algorithm job packet
        
        This property is protected.
        """
        ...

    @Job.setter
    def Job(self, value: QuantConnect.Packets.AlgorithmNodePacket):
        """
        Gets the algorithm job packet
        
        This property is protected.
        """
        ...

    @property
    def Algorithm(self) -> QuantConnect.Interfaces.IAlgorithm:
        """
        Gets the algorithm instance
        
        This property is protected.
        """
        ...

    @Algorithm.setter
    def Algorithm(self, value: QuantConnect.Interfaces.IAlgorithm):
        """
        Gets the algorithm instance
        
        This property is protected.
        """
        ...

    @property
    def MessagingHandler(self) -> QuantConnect.Interfaces.IMessagingHandler:
        """
        Gets the confgured messaging handler for sending packets
        
        This property is protected.
        """
        ...

    @MessagingHandler.setter
    def MessagingHandler(self, value: QuantConnect.Interfaces.IMessagingHandler):
        """
        Gets the confgured messaging handler for sending packets
        
        This property is protected.
        """
        ...

    @property
    def InsightManager(self) -> QuantConnect.Algorithm.Framework.Alphas.Analysis.IInsightManager:
        """
        Gets the insight manager instance used to manage the analysis of algorithm insights
        
        This property is protected.
        """
        ...

    @InsightManager.setter
    def InsightManager(self, value: QuantConnect.Algorithm.Framework.Alphas.Analysis.IInsightManager):
        """
        Gets the insight manager instance used to manage the analysis of algorithm insights
        
        This property is protected.
        """
        ...

    def Initialize(self, job: QuantConnect.Packets.AlgorithmNodePacket, algorithm: QuantConnect.Interfaces.IAlgorithm, messagingHandler: QuantConnect.Interfaces.IMessagingHandler, api: QuantConnect.Interfaces.IApi, transactionHandler: QuantConnect.Lean.Engine.TransactionHandlers.ITransactionHandler) -> None:
        """
        Initializes this alpha handler to accept insights from the specified algorithm
        
        :param job: The algorithm job
        :param algorithm: The algorithm instance
        :param messagingHandler: Handler used for sending insights
        :param api: Api instance
        :param transactionHandler: Algorithms transaction handler
        """
        ...

    def AddInsightManagerCustomExtensions(self, statistics: QuantConnect.Lean.Engine.Alphas.StatisticsInsightManagerExtension) -> None:
        """
        Allows each alpha handler implementation to add there own optional extensions
        
        This method is protected.
        """
        ...

    def OnAfterAlgorithmInitialized(self, algorithm: QuantConnect.Interfaces.IAlgorithm) -> None:
        """
        Invoked after the algorithm's Initialize method was called allowing the alpha handler to check
        other things, such as sampling period for backtests
        
        :param algorithm: The algorithm instance
        """
        ...

    def ProcessSynchronousEvents(self) -> None:
        """Performs processing in sync with the algorithm's time loop to provide consisten reading of data"""
        ...

    def Exit(self) -> None:
        """Stops processing and stores insights"""
        ...

    def StoreInsights(self) -> None:
        """
        Save insight results to persistent storage
        
        This method is protected.
        """
        ...

    def CreateInsightManager(self) -> QuantConnect.Algorithm.Framework.Alphas.Analysis.IInsightManager:
        """
        Creates the InsightManager to manage the analysis of generated insights
        
        This method is protected.
        
        :returns: A new insight manager instance.
        """
        ...


