示例#1
0
 def send(self, data: pd.DataFrame, attachments=[]):
     emaillist = [elem.strip().split(',') for elem in self.receivers]
     msg = MIMEMultipart()
     msg['Subject'] = "Test Report"
     msg['From'] = self.sender
     ### Email format ###
     html = """\
     <html>
       <head></head>
       <body>
         {0}
       </body>
     </html>
     """.format(data.to_html())
     part1 = MIMEText(html, 'html')
     msg.attach(part1)
     ### Attachment ###
     if attachments:
         for path in attachments:
             filename = os.path.split(path)[-1]
             with open(path, "rb") as attachment:
                 # Add file as application/octet-stream
                 # Email client can usually download this automatically as attachment
                 part = MIMEBase("application", "octet-stream")
                 part.set_payload(attachment.read())
             # Encode file in ASCII characters to send by email
             encoders.encode_base64(part)
             # Add header as key/value pair to attachment part
             part.add_header(
                 "Content-Disposition",
                 f"attachment; filename={filename}",
             )
             # Add attachment to message and convert message to string
             msg.attach(part)
     # Create a secure SSL context
     context = ssl.create_default_context()
     setting = Setting.get()
     # Try to log in to server and send email
     try:
         server = smtplib.SMTP(self.smtp_server, self.tls_port)
         server.ehlo()  # Can be omitted
         server.starttls(context=context)  # Secure the connection
         server.ehlo()  # Can be omitted
         server.login(self.sender, setting.sender_email_password)
         # Send email here
         server.sendmail(msg['From'], emaillist, msg.as_string())
         logger.info(f"Successfully send email to {emaillist}.")
     except Exception as e:
         # Print any error messages to stdout
         logger.error(str(e))
     finally:
         server.quit()
示例#2
0
def evaluate(assetId: str,
             strategyId: str,
             df: pd.DataFrame,
             evaluationPeriod: EvaluationPeriod = None,
             deleteTemp=False) -> bool:
    """
    Evaluate the performance of an arbitrary strategy. Columns required in df for evaluation process as below
    :param
        assetId:
        strategyId: ID of the strategy with the specific set of parameters that generate 'position' for data
        df: assume the existence of these columns after running through a Strategy
            position: determine the position of the asset at each point in time
    :return: the enriched df with evaluation parameters if pass evaluation criteria, else return None
    """
    name = '_'.join([assetId, strategyId, evaluationPeriod.name])
    ### evaluation parameters
    df['asset_ret'] = df['Adj Close'].pct_change()
    df['return'] = df['asset_ret'] * df['position']
    df['unit_asset_ret'] = (1 + df['asset_ret']).cumprod()
    df['value'] = (1 + df['return']).cumprod()
    ### evaluate
    if not deleteTemp:
        tempDir = None
        tempPath = get_temp_path()
        if not os.path.exists(tempPath):
            os.makedirs(tempPath)
    else:
        tempDir = tempfile.TemporaryDirectory()
        tempPath = tempDir.name
    graph_file_extension = Setting.get().graph_file_extension
    tempPath = os.path.join(tempPath, name)
    fig = plt.figure(figsize=(15, 10))
    s1 = fig.add_subplot(2, 1, 1)
    s1.plot(df['value'], label='Portfolio unit value')
    s1.plot(df['unit_asset_ret'], label='Asset unit value')
    s1.legend()
    s1.set_title("Return")
    s2 = fig.add_subplot(2, 1, 2)
    alpha = df['value'] - df['unit_asset_ret']
    s2.plot(alpha, label='Excess return compared to asset', color='r')
    s2.legend()
    s2.set_title("Alpha")
    fig.savefig(tempPath + f'.{graph_file_extension}',
                format=graph_file_extension)
    plt.close(fig)
    logger.info(f"Graph for {name} generated at {tempPath}.")
    if tempDir: tempDir.cleanup()
    ### TODO: define the criteria for a pass
    if not True:
        return None
    return df
示例#3
0
    :param n_jobs: the number of parallelized workers
    :return: list of results from workers, should have length == len(partitions)

    Note: can be implemented to submit jobs to distributed computing engine like a Spark cluster.
    For now, just implemented to utilize multicore in the host machine
    '''
    # p = Pool(n_jobs)
    # results = p.map(func, partitions)
    # TODO: apply parallelized version, results should maintain order as input partitions
    results = [func(*params) for params in partitions]
    return results


if __name__ == '__main__':
    # TODO: create Setting object and Context object
    settings = Setting.get()
    config = json.loads(open(settings.account_config_path).read())
    # TODO: error handling
    watchlist = list(
        filter(lambda wl: wl['watchlist_id'] == 'default',
               config['watchlists']))[0]
    asset_ids = watchlist['assets']
    ''' pass asset ids to Analyzer '''
    # 1. single-asset analyzer
    # 2. multi-asset analyzer
    ''' Analyzer askes Strategy for DataConfig (duration, frequency, parameters, etc.) to specify what to fetch from MarketData/Portfolio '''
    ''' Analyzer gets data from MarketData for these assets '''
    # what information you want ?
    # 1. trading info (price, volume, etc.)
    # 2. company info (BS, news, etc.)
    # assuming we get these config from Strategy
示例#4
0
import typing
import pandas as pd
import os
from reporting.reporter import EmailReporter
from settings import Setting
from utils import get_temp_path

graph_file_extension = Setting.get().graph_file_extension


def getGraphs(columns: pd.MultiIndex):
    index = columns.reorder_levels(['StrategyId', 'AssetId'])
    graphNames = map('_'.join, index.values.tolist())
    basePath = get_temp_path()
    return [
        os.path.join(basePath, f"{filename}.{graph_file_extension}")
        for filename in graphNames
    ]


def generateReport(data: pd.DataFrame):
    """
    :param data: mapping of asset_id to its signal data frame
    :return:
    """
    signals = data.xs('signal', axis=1, level='Attributes')
    ### email the following detail
    emailReporter = EmailReporter(['*****@*****.**'])
    attachments = getGraphs(signals.columns)
    emailReporter.send(signals.tail(10).sort_index(ascending=False),
                       attachments=attachments)
示例#5
0
 def __init__(self, receivers: typing.List[str]):
     super().__init__()
     self.sender = Setting.get().sender_email
     self.receivers = receivers