Overall Statistics
Total Trades
54041
Average Win
0.03%
Average Loss
-0.01%
Compounding Annual Return
24.771%
Drawdown
13.600%
Expectancy
0.277
Net Profit
204.419%
Sharpe Ratio
1.497
Probabilistic Sharpe Ratio
81.571%
Loss Rate
57%
Win Rate
43%
Profit-Loss Ratio
2.00
Alpha
0
Beta
0
Annual Standard Deviation
0.141
Annual Variance
0.02
Information Ratio
1.497
Tracking Error
0.141
Treynor Ratio
0
Total Fees
$215289.56
BrokerageSupportedSecurities = {
    "AlpacaBrokerageModel": [SecurityType.Equity],
    "AlphaStreamsBrokerageModel": [SecurityType.Equity, SecurityType.Forex, SecurityType.Crypto, SecurityType.Future, SecurityType.Option, SecurityType.Cfd, SecurityType.Base],
    "BitfinexBrokerageModel": [SecurityType.Crypto],
    "DefaultBrokerageModel": [SecurityType.Equity, SecurityType.Forex, SecurityType.Crypto, SecurityType.Future, SecurityType.Option, SecurityType.Cfd, SecurityType.Base],
    "FxcmBrokerageModel": [SecurityType.Forex, SecurityType.Cfd],
    "GDAXBrokerageModel": [SecurityType.Crypto],
    "InteractiveBrokersBrokerageModel": [SecurityType.Equity, SecurityType.Forex, SecurityType.Future, SecurityType.Option],
    "OandaBrokerageModel": [SecurityType.Forex, SecurityType.Cfd],
    "TradierBrokerageModel": [SecurityType.Equity]
}

def BrokerageErrorMessage(symbol, brokerage):
    ErrorMessage = {
        "AlpacaBrokerageModel": f"Alpaca Brokerage doesn't support trading {symbol.Value}.",
        "AlphaStreamsBrokerageModel": f"Alpha Streams Brokerage doesn't support data for {symbol.Value}.",
        "BitfinexBrokerageModel": f"Bitfinex Brokerage doesn't support trading {symbol.Value}.",
        "DefaultBrokerageModel": f"Default Brokerage doesn't support data for {symbol.Value}.",
        "FxcmBrokerageModel": f"FXCM Brokerage doesn't support trading {symbol.Value}.",
        "GDAXBrokerageModel": f"GDAX Brokerage doesn't support trading {symbol.Value}.",
        "InteractiveBrokersBrokerageModel": f"Interactive Brokers doesn't support trading {symbol.Value}.",
        "OandaBrokerageModel": f"Oanda Brokerage doesn't support trading {symbol.Value}.",
        "TradierBrokerageModel": f"Tradier Brokerage doesn't support trading {symbol.Value}."
    }

    return ErrorMessage[brokerage]
from AlphaStreamsSocket import *
from AlphaStreamsAlphaModel import *
from AlphaStream.AlphaStreamClient import *

class AlphaStreamsRunnerAlgorithm(QCAlgorithm):
    ''' Basic template QC Algorithm to backtest or trade live using Alpha insights '''

    def Initialize(self):
        # Set the brokerage model and account settings for Financial Advisor accounts

        self.SetBrokerageModel(AlphaStreamsBrokerageModel())

        # self.SetBrokerageModel(InteractiveBrokersBrokerageModel())
        # self.UniverseSettings.Leverage = 2.2
        # self.DefaultOrderProperties = InteractiveBrokersOrderProperties()
        # self.DefaultOrderProperties.Account = ""
        # self.DefaultOrderProperties.FaGroup = ""
        # self.DefaultOrderProperties.FaMethod = ""
        # self.DefaultOrderProperties.FaPercentage = ""
        # self.DefaultOrderProperties.FaProfile  = ""

        # Set AlphaStream ID and API token
        clientId = f'{self.GetParameter("clientId")}'
        clientToken = f'{self.GetParameter("clientToken")}'
        client = AlphaStreamClient(clientId, clientToken)
        self.client = client

        # # Create Alpha model(s)
        self.alphaIds = ["175bdd1036af614cfdc74dba9", "065fa592191da79dda29c8e37", "6d59e4088ef09a0aa316349dc", "083015f9d0b166d78ca7a71f7"]

        # # Build a dictionary containing the credentials necessary to stream Insights live
        RMQUserName = f'{self.GetParameter("RMQUserName")}'
        RMQPassword = f'{self.GetParameter("RMQPassword")}'
        RMQHostName = f'{self.GetParameter("RMQHostName")}'
        RMQVirtualHost = f'{self.GetParameter("RMQVirtualHost")}'
        RMQExchange = f'{self.GetParameter("RMQExchange")}'
        streamClientInformation = {'UserName':RMQUserName, 'Password':RMQPassword, 'HostName':RMQHostName,
                                  'VirtualHost':RMQVirtualHost, 'ExchangeName':RMQExchange, 'Port':5672}

        self.alphaModels = {id: AlphaStreamsAlphaModel(self, id, client) for id in self.alphaIds}

        # Add the alpha model(s) -- comma-separated arguments
        models = list(self.alphaModels.values())
        self.AddAlpha(CompositeAlphaModel(models[0], models[1], models[2], models[3]))

        # Set Start Date and End Date based on Alpha models
        # self.SetStartDate(min([x.StartDate for x in self.alphaModels.values()]))  # Set Start Date
        self.SetStartDate(2015, 4, 1)
        self.SetEndDate(max([x.EndDate for x in self.alphaModels.values()]))  # Set End Date
        self.SetCash(1000000)  # Set Strategy Cash

        # Initialize security prices using most recent historical data
        self.SetSecurityInitializer(self.HistoricalSecurityInitializer)

        # Use null benchmark to avoid brokerage/data conflicts
        self.SetBenchmark(lambda x: 0)

        # Set the portfolio construction model to turn Insights into Portfolio Targets
        self.SetPortfolioConstruction(InsightWeightingPortfolioConstructionModel(lambda time: None))

        # Set the execution model to turn Portfolio Targets into orders
        self.SetExecution(ImmediateExecutionModel())

        # Set Universe Selection
        self.SetUniverseSelection(CoarseFundamentalUniverseSelectionModel(self.CoarseSelectionFunction))

        # If trading live, stream the Insights
        if self.LiveMode:
            for id, model in self.alphaModels.items():
                model.EnsureState(client)
            self.socket = AlphaStreamsSocket(self, client, streamClientInformation, self.alphaIds)

        self.first = True

    def CoarseSelectionFunction(self, coarse):
        if self.first:
            symbols = []
            for model in list(self.alphaModels.values()):
                symbols += model.symbols
            symbols = list(set(symbols))
            self.first = False
            return symbols
        else:
            return Universe.Unchanged

    def HistoricalSecurityInitializer(self, security):
        if security.IsCustomData():
            return
        bar = self.GetLastKnownPrice(security)
        security.SetMarketPrice(bar)

    def OnEndOfAlgorithm(self):
        if self.LiveMode:
            for i in self.alphaIds:
                try:
                    self.client.Unsubscribe(i)
                    self.Log(f'Unsubscribed from {i}')
                except:
                    self.Log(f'Unable to unsubscribe from {i}. Please check your Institution page to check and manage your subscriptions.')

    def OnOrderEvent(self, orderEvent):
        order = self.Transactions.GetOrderById(orderEvent.OrderId)
        if orderEvent.Status == OrderStatus.Filled:
            self.Log("{0}: {1}: {2}".format(self.Time, order.Type, orderEvent))
class UnsubscribeRequest(object):
    """ Send subscription stop request for an Alpha """

    def __init__(self, alphaId):
        self.Id    = str(alphaId)
        self.Endpoint   = "alpha/" + self.Id + "/unsubscribe" 
        
    def GetPayload(self):
        payload = {
            "id"        : self.Id
        }
        return payload
class SubscribeRequest(object):
    """ Send subscription request for an Alpha """

    def __init__(self, alphaId, exclusive=False):
        self.Id    = str(alphaId)
        self.Endpoint   = "alpha/" + self.Id + "/subscribe"
        self.Exclusive  = exclusive
        
    def GetPayload(self):
        payload = {
            "id"        : self.Id,
            "exclusive" : self.Exclusive
        }
        return payload
from RabbitMQ.Client import *
from RabbitMQ.Client.Events import *

from System import *
from System import String, Object
from System.Text import *
from System.Collections.Generic import Dictionary

from QuantConnect import *
from QuantConnect.Data.Custom import *
from AlphaStream.AlphaStreamInsight import *

import json
from datetime import datetime


class AlphaStreamsSocket:
    '''
        Class to create and run threads for each Alpha being subscribed to. It creates threads,
        opens connections to the streaming Insights, and passes them on to the Alpha Model
        for each Alpha ID.
    '''

    def __init__(self, algorithm, client, streamClientInformation, alphaIds):
        '''
            Args:
                algorithm: QC Algorithm allows for logging and access to algorithm class
                client: Alpha Stream Client instance
                streamClientInformation: dictionary holding credentials necessary to establish the connection
        '''
        self.algorithm = algorithm

        # Added null data source to ensure Update() method fires every second
        self.algorithm.AddData(NullData, 'NullData', Resolution.Second)

        for alphaId in alphaIds:
            try:
                client.Subscribe(alphaId)
                self.algorithm.Log(f'Subscribing to {alphaId}')
            except:
                client.Unsubscribe(alphaId)
                client.Subscribe(alphaId)


        self.algorithm.Log(f'{datetime.now()} :: Creating RMQ factory')

        # Setting factory properties
        factory = ConnectionFactory()
        factory.HostName = streamClientInformation.get('HostName', None)
        factory.Port = streamClientInformation.get('Port', None)
        factory.UserName = streamClientInformation.get('UserName', None)
        factory.Password = streamClientInformation.get('Password', None)
        factory.VirtualHost = streamClientInformation.get('VirtualHost', None)
        factory.AutomaticRecoveryEnabled = True
        factory.RequestedConnectionTimeout = 5000

        connection = factory.CreateConnection()
        connection.ConnectionBlocked += self.OnConnectionBlocked
        connection.ConnectionShutdown += self.OnConnectionShutdown
        connection.ConnectionUnblocked += self.OnConnectionUnblocked
        connection.CallbackException += self.OnCallbackException

        # Open channel
        self.algorithm.Log(f'{datetime.now()} :: Opening RMQ channel')
        channel = connection.CreateModel()

        # Create consumer to receive messages
        self.algorithm.Log(f'{datetime.now()} :: Creating RMQ consumer')
        consumer = EventingBasicConsumer(channel)
        consumer.Received += self.ConsumerOnReceived


        dict1 = Dictionary[String, Object]()
        dict1["x-message-ttl"] = 60000

        self.algorithm.Log(f'{datetime.now()} :: Creating RMQ Queue')
        channel.QueueDeclare("AlphaStreamsRunner", False, False, True, dict1)
        channel.QueueBind("AlphaStreamsRunner", streamClientInformation.get("ExchangeName", None), f'*', dict1)
        channel.BasicConsume("AlphaStreamsRunner", True, "", False, False, dict1, consumer)
        self.algorithm.Log(f'{datetime.now()} :: RMQ connection established')

    def OnConnectionBlocked(self, sender, args):
        self.algorithm.Log(f"RMQHelper.OnConnectionBlocked(): Connection is blocked: {args.Reason}")

    def OnConnectionShutdown(self, sender, args):
        self.algorithm.Log(f"RMQHelper.OnConnectionShutdown(): Connection is shutdown: {args.Reason}")

    def OnConnectionUnblocked(self, sender, args):
        self.algorithm.Log(f"RMQHelper.OnConnectionUnblocked(): Connection is unblocked: {args.Reason}")

    def OnCallbackException(self, sender, args):
        self.algorithm.Log(f"RMQHelper.OnCallbackException(): Callback exception: {args.Reason}")

    def ConsumerOnReceived(self, sender, e):
        ''' Consumes and processes the messages received via the channel '''
        try:
            stringDictionary = Encoding.UTF8.GetString(e.Body)
            packet = json.loads(stringDictionary)
            self.algorithm.Log(f'{datetime.now()} :: Routing Key: {e.get_RoutingKey()} :: Exchange: {e.get_Exchange()} :: Consumer tag: {e.get_ConsumerTag()} :: Delivery tag: {e.get_DeliveryTag()}')
            messageType = packet.get("eType", None)
            alphaId = packet.get("alpha-id", None)
            model = self.algorithm.alphaModels.get(alphaId, None)

            if model is None:
                # raise Exception (f'Message received from different Alpha: {alphaId}. Check Queue bindings, shutting down algorithm.')
                return

            if messageType == "AlphaResult":
                insights = packet.get("insights", [])
                for insight in insights:
                    self.algorithm.Log(f'{self.algorithm.Time} :: {alphaId} received Insight. Converting to framework Insight')
                    asi = AlphaStreamInsight(insight)
                    model.Listener(model.AlphaInsightToFrameworkInsight(asi, alphaId))  # Send streamed Insights back into Alpha model

            elif messageType == "AlphaHeartbeat":
                self.algorithm.Log(f'Model: {model.Id}')
                algorithmId = packet.get("algorithm-id", None)
                machineTime = packet.get("machine-time", None)
                self.algorithm.Log(f'Heartbeat :: alphaId: {model.Id} -- algo ID: {algorithmId} :: {machineTime}\n')
            else:
                raise Exception(f"Invalid type: {messageType}")

        except Exception as err:
            self.algorithm.Log(f"Failed parsing deliver event: {err}")
import threading
from itertools import groupby
from datetime import timedelta, datetime
from BrokerageSupportedSecurities import *


class AlphaStreamsAlphaModel(AlphaModel):
    '''
        Alpha Model that backtests and streams live Insights. Backtest Insights are collected in batch
        and then iterated over. Live Insights are streamed and emitted in real-time.

        Arguments:
            algorithm: QCAlgorithm that is being run
            alphaId: ID of the Alpha being tested
            client: AlphaStreamsClient to fetch Insights
    '''

    def __init__(self, algorithm, alphaId, client):

        self.StartDate = datetime(1900, 1, 1)
        self.EndDate = datetime(2050, 1, 1)
        self.Id = alphaId
        self.lock = threading.Lock()

        self.liveInsightCollection = []
        self.backtestInsightCollection = {}
        self.backtestInsightIndex = 0
        self.algorithm = algorithm
        self.supportedSecurities = BrokerageSupportedSecurities[str(algorithm.BrokerageModel)[24:]]
        self.dataResolution = {}
        self.canExecute = []
        self.symbols = []
        if not algorithm.LiveMode:
            insights = []
            hasData = True
            start = 0

            # Fetch all Insights in the Alpha's backtest
            while hasData:
                responseInsights = client.GetAlphaInsights(alphaId, start)  # Fetch alpha Insights (backtest and live)
                insights += [self.AlphaInsightToFrameworkInsight(x, alphaId) for x in responseInsights if
                             x.Source in ['in sample', 'live trading']]
                hasData = len(responseInsights)
                start += 100

            # Raise exception if there are no Insights
            if len(insights) == 0:
                # raise Exception(f'No insights from alpha {alphaId}')
                algorithm.Log(f'No insights from alpha {alphaId}')
                self.backtestInsightKeys = []
                self.StartDate = algorithm.Time
                self.EndDate = algorithm.Time
                self.dataResolution = Resolution.Minute
                return
                
            # Group insights by time created
            self.backtestInsightCollection = {k: list(g) for k, g in
                                              groupby(sorted(insights, key=lambda x: x.GeneratedTimeUtc),
                                                      key=lambda x: x.GeneratedTimeUtc)}
            self.backtestInsightKeys = list(self.backtestInsightCollection.keys())  # Create list of dictionary keys
            self.StartDate = self.backtestInsightKeys[0]  # Get date of first Insight
            self.EndDate = self.backtestInsightKeys[-1] + list(self.backtestInsightCollection.values())[-1][ 0].Period  # Get date of last Insight
            self.dataResolution = {x.Symbol: Resolution.Minute if x.GeneratedTimeUtc.second == 0 else Resolution.Second for x in list(set([item for sublist in list(self.backtestInsightCollection.values()) for item in sublist]))}  # List of data resolution for each symbol
            self.symbols = [x.Symbol for x in insights]

    def Update(self, algorithm, data):
        ''' Updates this alpha model with the latest data from the algorithm.
            This is called each time the algorithm receives data for subscribed securities
            Args:
                algorithm: The algorithm instance
                data: The new data available
            Returns:
                The insights
        '''
        insights = []

        # Fetch Insights to be emitted
        if algorithm.LiveMode:
            # Lock thread to modify insight collection
            self.lock.acquire()
            insights = [self.liveInsightCollection.pop(self.liveInsightCollection.index(x)) for x in self.liveInsightCollection if (x.GeneratedTimeUtc <= algorithm.UtcTime.replace(tzinfo=None)) and (algorithm.ActiveSecurities.ContainsKey(x.Symbol))]
            self.lock.release()
        
        if len(self.backtestInsightKeys) == 0:
            return []

        else:
            if self.backtestInsightIndex == len(self.backtestInsightKeys):
                return []

            algoTime = algorithm.UtcTime.replace(tzinfo=None)
            while algoTime >= self.backtestInsightKeys[self.backtestInsightIndex]:
                if (self.backtestInsightCollection[self.backtestInsightKeys[self.backtestInsightIndex]] is None) or (insights is None):
                    x = 5
                insights += self.backtestInsightCollection[self.backtestInsightKeys[self.backtestInsightIndex]]
                if self.backtestInsightIndex is None:
                    x = 5
                self.backtestInsightIndex += 1
                if self.backtestInsightIndex == len(self.backtestInsightKeys):
                    break

        for i in insights:
            if i.CloseTimeUtc <= algoTime:
                insights.pop(insights.index(i))
            algorithm.Log(f'{algorithm.Time} :: In {self.Id} Update(), emitting Insight: {i.ToString()}')

        return insights
        
    def Listener(self, insight):
        ''' Called in the thread when messages are received via Rabbit MQ. It checks if
            data needs to be added for the new Insight and then adds the Insight to the
            Insight collection.

            Args:
                insight: Insight streamed from the live Alpha
        '''

        # Check that the security type is supported by the brokerage model, else kill algorithm
        self.EnsureExecution(insight.Symbol)

        # Add data for the Insight Symbol if necessary
        self.EnsureData(insight.Symbol)

        # Lock thread to modify insight collection
        self.lock.acquire()
        self.liveInsightCollection += [insight]
        self.lock.release()
        self.algorithm.Log(f'{self.algorithm.Time} :: In {self.Id} Listener(), adding Insight: {insight.ToString()}')

    def EnsureState(self, client):
        ''' Called in QCAlgorithm Initialize() for each Alpha model. Checks to see if there are any Insights that are
            currently live and creates Insights to mirror them.
            Args:
                client: AlphaStreamClient instance
        '''
        insights = []
        hasData = True
        alpha = client.GetAlphaById(self.Id)
        start = alpha.InSampleInsights + alpha.LiveTradingInsights + alpha.OutOfSampleInsights - 100

        # Fetch most recent Insights to see if there are any live trading Insights that haven't expired yet
        while hasData:
            responseInsights = client.GetAlphaInsights(self.Id, start)[::-1]
            # In case our initial "start" value is too large and won't fetch any Insights
            if len(responseInsights) < 1:
                if start < 0:
                    # Raise exception if we haven't found any Insights at all
                    raise Exception(f"No Insights found for {self.Id} while trying to ensure state")
                start -= 100
                continue
            # Filter for Insights whose CloseTime is > algorithm time
            liveInsights = [self.AlphaInsightToFrameworkInsight(x, self.Id) for x in responseInsights if (x.Source == 'live trading') and (self.algorithm.UtcTime.replace(tzinfo=None) < x.CloseTime)]
            insights += liveInsights
            hasData = len(liveInsights)
            start -= 100

        if len(insights) > 0:
            # Data check for all Insights
            for insight in insights:
                # Check that the security type is supported by the brokerage model
                self.EnsureExecution(insight.Symbol)
                # Add data for the Insight Symbol if necessary
                self.EnsureData(insight.Symbol)

            # Lock thread and modify insight collection
            self.lock.acquire()
            self.liveInsightCollection += insights
            self.lock.release()

            self.algorithm.Log(f'{self.algorithm.Time} :: In {self.Id} Alpha Model, adding currently live insights')

    def EnsureExecution(self, symbol):
        ''' Called from Listener() to see if the security type of the Insight can be traded on the selected brokerage

            Args:
                insight: Framework Insight being streamed in
            Returns: True if brokerage supports the security type, false otherwise
        '''
        if symbol in self.canExecute:
            return

        if symbol.SecurityType not in self.supportedSecurities:
            self.algorithm.Quit(f'{BrokerageErrorMessage(symbol, str(self.algorithm.BrokerageModel)[24:])}')
        else:
            self.canExecute += [symbol]
        
    def EnsureData(self, symbol):
        ''' Called from Listener method to see if data needs to be added for new Insights

            Args:
                symbol: Symbol of the asset underlying the Insight
        '''
        if not self.algorithm.Securities.ContainsKey(symbol):
            symbolResolution = Resolution.Second
            if not self.algorithm.LiveMode:
                symbolResolution = self.dataResolution[symbol]
            self.algorithm.AddSecurity(symbol.SecurityType, symbol.Value, symbolResolution, symbol.ID.Market, True, 0, False)


    # Converts AlphaStream Insight types to QC Insight types
    def AlphaInsightToFrameworkInsight(self, alphaInsight, alphaId = None):
        ''' Converts Alpha Stream Insights to QC Algorithm Framework Insights, which is the format
            required.

            Args:
                alphaInsight: Alpha Streams Insight (live or backtest)

            Returns:
                insight: QC Algorithm Framework Insight
        '''
        if alphaInsight.Direction.lower() == 'up':
            direction = InsightDirection.Up
        elif alphaInsight.Direction.lower() == 'down':
            direction = InsightDirection.Down
        else:
            direction = InsightDirection.Flat

        ## Try using insight ticker, not symbol
        
        ## plan B -- coarse universe is created to use symbols, not tickers
        symbol = self.algorithm.Symbol(alphaInsight.Symbol)

        insight = Insight(symbol, timedelta(seconds=alphaInsight.Period), InsightType.Price,
                          direction, alphaInsight.Magnitude, alphaInsight.Confidence,
                          alphaId if alphaId is not None else alphaInsight.SourceModel,
                          alphaInsight.Weight)

        insight.GeneratedTimeUtc = alphaInsight.CreatedTime if alphaInsight.CreatedTime is not None else alphaInsight.GeneratedTimeUtc
        insight.CloseTimeUtc = insight.GeneratedTimeUtc + insight.Period

        self.algorithm.Log(f'{alphaInsight.Symbol} :: AS Insight ID {alphaInsight.Id} ---> Framework Insight ID {insight.Id} :: Alpha ID: {self.Id}')
        return insight
# Your New Python File
import json
import requests
import hashlib
import time
import base64
import os
import pandas as pd
from datetime import datetime
from AlphaStreamInsight import *
from GetAlphaInsightsRequest import *
from SubscribeRequest import *
from UnsubscribeRequest import *
from GetAlphaByIdRequest import *
from AlphaStreamsAlpha import *

class AlphaStreamClient(object):
    """Alpha Streams Client is the REST executor and client """

    def __init__(self, *args, **kwargs):
        self.__clientId =  str(kwargs.pop('clientId', args[0]))
        self.__token = str(kwargs.pop('token', args[1]))
        self.__url = 'https://www.quantconnect.com/api/v2/'

    def Execute(self, request, debug=False):
        """ Execute an authenticated request to the Alpha Streams API """

        # Create authenticated timestamped token.
        timestamp = str(int(time.time()))

        # Attach timestamp to token for increasing token randomness
        timeStampedToken = self.__token + ':' + timestamp

        # Hash token for transport
        apiToken = hashlib.sha256(timeStampedToken.encode('utf-8')).hexdigest()

        # Attach in headers for basic authentication.
        authentication = "{}:{}".format(self.__clientId, apiToken)
        base64string = base64.b64encode(authentication.encode('utf-8'))
        headers = {
            'Authorization': 'Basic %s' % base64string.decode('ascii'),
            'Timestamp': timestamp
        }

        # URL endpoint specified in request
        url = self.__url + request.Endpoint

        # Encode the request in parameters of URL. Most of API is GET.
        result = requests.get(url, params=request.GetPayload(), headers=headers)

        if debug:
            print(result.url)
            self.PrettyPrint(result)

        # Convert to object for parsing.
        try:
            json = result.json()
        except Exception as err:
            messages = []
            messages.append(
                'API returned a result which cannot be parsed into JSON. Please inspect the raw result below:')
            messages.append(result.text)
            json = {'success': False, 'messages': messages}

        if type(json) is not list:
            if ('success' in json.keys()) and ('messages' in json.keys()):
                if json['success'] is False:
                    raise Exception(
                        'There was an exception processing your request: {}'.format(", ".join(json["messages"]), json))
            elif ('success' in json.keys()):
                if json['success'] is False:
                    raise Exception(
                        'There was an exception processing your request: {}'.format(json))
            else:
                raise Exception(
                    'There was an exception processing your request: {}'.format(json))
        return json

    def GetAlphaById(self, alphaId):
        """ Request details about a specific alpha """
        request = GetAlphaByIdRequest(alphaId)
        result = self.Execute(request)
        return AlphaStreamsAlpha(result)

    def GetAuthorById(self, authorId):
        """ Get information about a specific author """
        request = GetAuthorByIdRequest(authorId)
        result = self.Execute(request)
        return Author(result)

    def GetAlphaInsights(self, alphaId, start=0):
        """ Get the insights for a specific alpha """
        request = GetAlphaInsightsRequest(alphaId, start)
        result = self.Execute(request)
        insights = []
        for i in result:
            insights.append(AlphaStreamInsight(i))
        return insights

    def GetAlphaQuotePrices(self, alphaId, start=0):
        """ Get the prices for a specific alpha """
        request = GetAlphaPricesRequest(alphaId, start)
        result = self.Execute(request)
        prices = []
        for i in result:
            prices.append(Price(i))
        return prices

    def GetAlphaErrors(self, alphaId, start=0):
        """ Get the errors for a specific alpha """
        request = GetAlphaErrorsRequest(alphaId, start)
        result = self.Execute(request)
        errors = []
        for i in result:
            errors.append(RuntimeError(i))
        return errors

    def GetAlphaEquityCurve(self, alphaId, date_format = 'date'):
        """ Get the pandas DataFrame with the equity curve for a specific alpha """
        request = GetAlphaEquityCurveRequest(alphaId, date_format)
        result = self.Execute(request)
        for i in result:
            if isinstance(i[0], int):
                i[0] = datetime.utcfromtimestamp(i[0])
            else:
                i[0] = datetime.strptime(i[0], "%d/%m/%Y %H:%M:%S")
        return pd.DataFrame.from_records(result, index=['time'], columns=['time', 'equity', 'sample'])


    def GetAlphaList(self):
         """ Get list of all available alpha Ids """
         request = GetAlphaListRequest()
         return self.Execute(request)

    def SearchAlphas(self, *args, **kwargs):
        """ Applying the search criteria supplied; find matching alphas and return an array of alpha objects """
        criteria = SearchAlphasRequest(kwargs=kwargs)
        result = self.Execute(criteria)

        alphas = []
        for a in result:
            alphas.append(Alpha(a))

        return alphas

    def SearchAuthors(self, *args, **kwargs):
        """ Applying the search criteria supplied; find matching authors and return an array of author objects """
        criteria = SearchAuthorsRequest(kwargs=kwargs)
        result = self.Execute(criteria)

        authors = []
        for ath in result:
            authors.append(Author(ath))

        return authors

    def Subscribe(self, alphaId):
        """ Subscribe to an alpha """
        request = SubscribeRequest(alphaId)
        result = self.Execute(request)
        return result['success']

    def Unsubscribe(self, alphaId):
        """ Unsubscribe from an alpha """
        request = UnsubscribeRequest(alphaId)
        result = self.Execute(request)
        return result['success']

    def CreateConversation(self, alphaId, email, subject, message, cc = ''):
        """ Create a conversation thread. """
        request = CreateConversationRequest(alphaId, email, subject, message, cc)
        result = self.Execute(request)
        if result['success']:
            return 'Conversation thread was successfully created.'
        else:
            return os.linesep.join(result['messages'])

    def ReadConversation(self, alphaId):
        """ Read a conversation thread to confirm receipt and return list of Conversation objects. """
        request = CreateReadRequest(alphaId)
        result = self.Execute(request)
        conversations = [Conversation(i) for i in result]
        return conversations


    def CreateBid(self, *args, **kwargs):
        """ Create a bid price request.
       Args:
            alphaId: Unique id hash of an Alpha published to the marketplace.
            exclusive: Bid for the exclusive price (optional if shared is defined).
            shared: Bid for the shared price (optional if exclusive is defined).
            good_until: Expiration time of the bid."""
        request = CreateBidPriceRequest(*args, **kwargs)
        result = self.Execute(request)
        if result['success']:
            return 'Bid price was successfully created.'
        else:
            return os.linesep.join(result['messages'])

    def PrettyPrint(self, result):
        """ Print out a nice formatted version of the request """
        print ('')
        try:
            parsed = json.loads(result.text)
            print (json.dumps(parsed, indent=4, sort_keys=True))
        except Exception  as err:
            print ('Fall back error (text print)')
            print ('')
            print (result.text)
        print ('')
from datetime import datetime


class AlphaStreamInsight:
    """Individual prediction/insight generated by an Alpha in the QuantConnect Alpha Streams market"""

    def __init__(self, json):
        self.Id = json['id']

        self.Type = json.get('type', None)

        self.Direction = json.get('direction', None)

        self.Period = json.get('period', None)
        
        self.CreatedTime = datetime.utcfromtimestamp(json['created-time']) if 'created-time' in json else None
        
        self.GeneratedTimeUtc = datetime.utcfromtimestamp(json['generated-time']) if 'generated-time' in json else None

        self.CloseTime = datetime.utcfromtimestamp(json['close-time']) if 'close-time' in json else None

        self.Magnitude = json.get('magnitude', None)

        self.Confidence = json.get('confidence', None)

        self.SourceModel = json.get('source-model', None)

        self.Group = json.get('group', None)

        self.Source = json.get('source', None)  # In sample

        self.ReferenceValue = json.get('reference-value', None)

        self.EstimatedValue = json.get('estimated-value', None)

        self.Symbol = json.get('symbol', None)

        self.Ticker = json.get('ticker', None)

        self.Invalid = json.get('invalid', None)

        self.ScoreFinal = json.get('score-final', False)

        self.Weight = json.get('weight', None)

    def __repr__(self):
        return f'{self.CreatedTime} Alpha {self.Source} {self.Type} insight for {self.Ticker:<10} going {self.Direction} over the next {self.Period}s'
class GetAlphaInsightsRequest:
    """ Fetch an alpha insights, starting from `start` for a maximum of 1000 insights """

    def __init__(self, alphaId, start = 0):
        self.Id = alphaId
        self.Start = start
        self.Endpoint = "alpha/{}/insights".format(alphaId)
        
    def GetPayload(self):
        payload = {
            "id" : self.Id,
            "start" : self.Start
        }
        return payload
class GetAlphaByIdRequest(object):
    """ Request a specific alpha with a matching Alpha Id """

    def __init__(self, alphaId):
        self.Id = str(alphaId)
        self.Endpoint = "alpha/" + self.Id
        
    def GetPayload(self):
        payload = {
            "id" : self.Id
        }
        return payload
class AlphaStreamsAlpha(object):
    """Algorithm alpha model from the Alpha Streams marketplace."""

    def __init__(self, json):

        self.Id = json['id']

        self.AssetClasses = json.get('asset-classes', None)

        self.Accuracy = json.get('accuracy', None)

        self.AnalysesPerformed = json.get('analyses-performed', None)

        self.AuthorTrading = json.get('author-trading', False)

        self.Description = json.get('description', '')

        self.EstimatedDepth = json.get('estimated-depth', None)

        self.ExclusiveAvailable = json.get('exclusive-available', None)

        self.ExclusiveSubscriptionFee = json.get('exclusive-subscription-fee', None)

        self.EstimatedEffort = json.get('estimated-effort', None)

        self.ListedTime = datetime.utcfromtimestamp(json['listed-time']) if 'listed-time' in json else None

        self.Name = json.get('name', None)

        self.Uniqueness = json.get('uniqueness', None)

        self.SharpeRatio = json.get('sharpe-ratio', None)

        self.SharedSubscriptionFee = json.get('subscription-fee', None)

        self.Version = json.get('version', None)

        self.Status = json.get('status', None)
        
        self.InSampleInsights = json.get('in-sample-insights', None)

        self.LiveTradingInsights = json.get('live-trading-insights', None)

        self.OutOfSampleInsights = json.get('out-of-sample-insights', None)

        self.Tags = json.get('tags', [])

        self.Parameters = json.get('parameters', None)

        self.OutOfSampleDtwDistance = json.get('out-of-sample-dtw-distance', None)

        self.OutOfSampleReturnsCorrelation = json.get('out-of-sample-returns-correlation', None)

        self.Trial = json.get('trial', 0)

    def __repr__(self):
        return f'''
Alpha Id: {self.Id}
    Project: {self.Project.Name}
    Sharpe Ratio: {self.SharpeRatio}
    Uniqueness: {self.Uniqueness}
    Exclusive Available: {self.ExclusiveAvailable}
    Listed: {self.ListedTime}
    Status: {self.Status}'''