def rewards(port,
            startdate,
            enddate,
            maxval,
            lambda1,
            lambda2,
            lambda3,
            cacheddir=None):
    df = port.get_portfolio_values_overtime(startdate,
                                            enddate,
                                            cacheddir=cacheddir)
    prices = np.array(df['value'])
    timestamps = np.array(df['TimeStamp'], dtype='datetime64[s]')

    r, sigma = fit_BlackScholesMerton_model(timestamps, prices)
    downside_risk = estimate_downside_risk(timestamps, prices, 0.)

    eachsymbol_prices = {
        symbol: nbshares *
        get_symbol_closing_price(symbol, enddate, cacheddir=cacheddir)
        for symbol, nbshares in port.symbols_nbshares.items()
    }
    totalprices = np.sum([val for val in eachsymbol_prices.values()])
    entropy = np.sum([
        val * (np.log(totalprices / val)) if val > 0 else 0.
        for val in eachsymbol_prices.values()
    ])
    entropy /= totalprices

    reward = r \
             - lambda1*sigma \
             + lambda2 * entropy / np.log(len(eachsymbol_prices)) \
             - lambda3 * downside_risk \
             + totalprices / maxval
    return reward
async def async_compute_symbol_info(symbol,
                                    startdate,
                                    enddate,
                                    cacheddir=None,
                                    waittime=1):
    symdf = await waiting_get_yahoofinance_data(symbol,
                                                startdate,
                                                enddate,
                                                cacheddir=cacheddir,
                                                waittime=waittime)
    if len(symdf) > 0:
        try:
            isrownull = symdf['Close'].isnull()
            r, sigma = fit_BlackScholesMerton_model(
                np.array(symdf.loc[~isrownull, 'TimeStamp']),
                np.array(symdf.loc[~isrownull, 'Close']))
            downside_risk = estimate_downside_risk(
                np.array(symdf.loc[~isrownull, 'TimeStamp']),
                np.array(symdf.loc[~isrownull, 'Close']), 0.0)
            upside_risk = estimate_upside_risk(
                np.array(symdf.loc[~isrownull, 'TimeStamp']),
                np.array(symdf.loc[~isrownull, 'Close']), 0.0)
            estimations = {
                'symbol':
                symbol,
                'r':
                r,
                'vol':
                sigma,
                'downside_risk':
                downside_risk,
                'upside_risk':
                upside_risk,
                'startdate':
                symdf['TimeStamp'][0].date().strftime('%Y-%m-%d'),
                'enddate':
                symdf['TimeStamp'][-1].date().strftime('%Y-%m-%d'),
                'nbrecs':
                len(symdf.loc[~isrownull, :]),
                'description':
                list(concernedsymdf['description'][concernedsymdf['symbol'] ==
                                                   symbol])[0],
                'type':
                list(concernedsymdf['type'][concernedsymdf['symbol'] ==
                                            symbol])[0]
            }
        except ZeroDivisionError:
            logging.warning(
                'Division by zero error for symbol {}; skipping.'.format(
                    symbol))
            estimations = {}
        except TypeError:
            logging.error('TypeError: symbol: {}; df: {}'.format(
                symbol, len(symdf)))
            estimations = {}
    else:
        estimations = {}

    return estimations
        'with' if with_dividends else 'without'))
    for symbol, nbshares in optimized_dynport.symbols_nbshares.items():
        print('{}: {}'.format(symbol, nbshares))

    # further imformation
    print('reward function: {}'.format(rewardfcn(optimized_dynport)))
    df = optimized_dynport.get_portfolio_values_overtime(startdate,
                                                         enddate,
                                                         cacheddir=cacheddir)
    # df['TimeStamp'] = df['TimeStamp'].map(lambda item: datetime.strftime(item, '%Y-%m-%d'))
    indexdf = get_yahoofinance_data(indexsymbol,
                                    startdate,
                                    enddate,
                                    cacheddir=cacheddir)
    indexdf['TimeStamp'] = indexdf['TimeStamp'].map(
        lambda item: datetime.strftime(item, '%Y-%m-%d'))
    indexdf.index = list(indexdf['TimeStamp'])
    df = df.join(indexdf, on='TimeStamp', how='left', rsuffix='2')
    df['Close'] = df['Close'].ffill()
    timestamps = np.array(df['TimeStamp'], dtype='datetime64[s]')
    prices = np.array(df['value'])
    r, sigma = fit_BlackScholesMerton_model(timestamps, prices)
    print('Yield: {}'.format(r))
    print('Volatility: {}'.format(sigma))
    downside_risk = estimate_downside_risk(timestamps, prices, 0.)
    print('Downside risk: {}'.format(downside_risk))
    upside_risk = estimate_upside_risk(timestamps, prices, 0.)
    print('Upside risk: {}'.format(upside_risk))
    beta = estimate_beta(timestamps, prices, np.array(df['Close']))
    print('Beta (relative to {}): {}'.format(indexsymbol, beta))
示例#4
0
def symbol_handler(event, context):
    # getting info
    logging.info(event)
    logging.info(context)
    query = json.loads(event['body'])

    # getting user inputs
    symbol = query['symbol']
    startdate = query['startdate']
    enddate = query['enddate']
    waittime = query.get('waittime', 1)
    index = query.get('index', 'DJI')  # DJI index as the base.

    # getting stock data
    symdf = waiting_get_yahoofinance_data(symbol,
                                          startdate,
                                          enddate,
                                          waittime=waittime)

    # getting index
    indexdf = waiting_get_yahoofinance_data(index,
                                            startdate,
                                            enddate,
                                            waittime=waittime)

    # estimation
    isrownull = symdf['Close'].isnull()
    r, sigma = fit_BlackScholesMerton_model(
        np.array(symdf.loc[~isrownull, 'TimeStamp']),
        np.array(symdf.loc[~isrownull, 'Close']))
    downside_risk = estimate_downside_risk(
        np.array(symdf.loc[~isrownull, 'TimeStamp']),
        np.array(symdf.loc[~isrownull, 'Close']), 0.0)
    upside_risk = estimate_upside_risk(
        np.array(symdf.loc[~isrownull, 'TimeStamp']),
        np.array(symdf.loc[~isrownull, 'Close']), 0.0)
    try:
        beta = estimate_beta(
            np.array(symdf.loc[~isrownull, 'TimeStamp']),
            np.array(symdf.loc[~isrownull, 'Close']),
            np.array(indexdf.loc[~isrownull, 'Close']),
        )
    except:
        logging.warning('Index {} failed to be integrated.'.format(index))
        beta = None

    estimations = {
        'symbol': symbol,
        'r': float(r),
        'vol': float(sigma),
        'downside_risk': float(downside_risk),
        'upside_risk': float(upside_risk),
        'beta': float(beta) if beta is not None else None,
        'data_startdate': symdf['TimeStamp'][0].date().strftime('%Y-%m-%d'),
        'data_enddate': symdf['TimeStamp'][-1].date().strftime('%Y-%m-%d'),
        'nbrecs': len(symdf.loc[~isrownull, :]),
    }

    req_res = {
        'isBase64Encoded': False,
        'statusCode': 200,
        # 'headers': {'Content-Type': 'application/json'},
        'body': json.dumps(estimations)
    }

    return req_res
def simulated_annealing_handler(event, context):
    # parsing argument
    query = event['body']
    startdate = query['startdate']
    enddate = query['enddate']
    maxval = query['maxval']
    symbols = query['symbols']
    nbsteps = query.get('nbsteps', 10000)
    init_temperature = query.get('init_temperature', 1000.)
    decfactor = query.get('decfactor', 0.75)
    temperaturechange_step = query.get('temperaturechange_step', 100)
    with_dividends = query.get('with_dividends', True)
    lambda1 = query.get('lambda1', 0.3)
    lambda2 = query.get('lambda2', 0.01)
    lambda3 = query.get('lambda3', 0.0)
    indexsymbol = query.get('index', 'DJI')
    call_wrapper = False
    if 'email' in query:
        assert 'sender_email' in query
        assert 'filebasename' in query
        call_wrapper = True

    # making caching directory
    cacheddir = '/tmp/cacheddir'

    logging.info('Portfolio Optimization Using Simulated Annealing')
    logging.info('Symbols: {}'.format(', '.join(symbols)))
    logging.info('Start date: {}'.format(startdate))
    logging.info('End date: {}'.format(enddate))
    logging.info('Maximum value of the portfolio: {}'.format(maxval))
    logging.info('Number of steps: {}'.format(nbsteps))
    logging.info('Initial temperature: {} (decreased every {} steps)'.format(
        init_temperature, temperaturechange_step))
    logging.info('Consider dividends? {}'.format(with_dividends))
    logging.info('Cached directory: {}'.format(cacheddir))
    logging.info('lambda1: {}'.format(lambda1))
    logging.info('lambda2: {}'.format(lambda2))
    logging.info('lambda3: {}'.format(lambda3))
    logging.info('indexsymbol: {}'.format(indexsymbol))

    # initializing the porfolio
    dynport = DynamicPortfolioWithDividends({symbol: 1
                                             for symbol in symbols},
                                            startdate,
                                            cacheddir=cacheddir)
    dynport.move_cursor_to_date(enddate)
    current_val = dynport.get_portfolio_value(enddate)
    if current_val > maxval:
        return {
            'statusCode':
            400,
            'body':
            json.dumps(
                'Too many symbols (or maximum portfolio value too small). Value ({}) > maxval ({})'
                .format(current_val, maxval))
        }

    # simulated annealing
    starttime = time.time()
    rewardfcn = partial(rewards,
                        startdate=startdate,
                        enddate=enddate,
                        maxval=maxval,
                        lambda1=lambda1,
                        lambda2=lambda2,
                        lambda3=lambda3,
                        cacheddir=cacheddir)
    optimized_dynport = simulated_annealing(
        dynport,
        rewardfcn,
        maxval,
        initT=init_temperature,
        factor=0.75,
        nbsteps=nbsteps,
        temperaturechangestep=temperaturechange_step,
        with_dividends=True)
    endtime = time.time()

    logging.info('final reward function: {}'.format(
        rewardfcn(optimized_dynport)))
    df = optimized_dynport.get_portfolio_values_overtime(startdate,
                                                         enddate,
                                                         cacheddir=cacheddir)
    indexdf = get_yahoofinance_data(indexsymbol,
                                    startdate,
                                    enddate,
                                    cacheddir=cacheddir)
    indexdf['TimeStamp'] = indexdf['TimeStamp'].map(
        lambda item: datetime.strftime(item, '%Y-%m-%d'))
    indexdf.index = list(indexdf['TimeStamp'])
    df = df.join(indexdf, on='TimeStamp', how='left', rsuffix='2')
    df['Close'] = df['Close'].ffill()
    timestamps = np.array(df['TimeStamp'], dtype='datetime64[s]')
    prices = np.array(df['value'])
    r, sigma = fit_BlackScholesMerton_model(timestamps, prices)
    downside_risk = estimate_downside_risk(timestamps, prices, 0.)
    upside_risk = estimate_upside_risk(timestamps, prices, 0.)
    beta = estimate_beta(timestamps, prices, np.array(df['Close']))

    result = {
        'r': r,
        'sigma': sigma,
        'downside_risk': downside_risk,
        'upside_risk': upside_risk,
        'beta': beta,
        'portfolio': optimized_dynport.generate_dynamic_portfolio_dict(),
        'runtime': endtime - starttime
    }

    if call_wrapper:
        lambda_client = boto3.client('lambda')
        lambda_client.invoke(
            FunctionName=
            'arn:aws:lambda:us-east-1:409029738116:function:portfolio-simulated-annealing-wrapper',
            InvocationType='Event',
            Payload=json.dumps(
                {'body': json.dumps({
                    'query': query,
                    'result': result
                })}))

    return {'statusCode': 200, 'body': json.dumps(result)}
示例#6
0
def portfolio_handler(event, context):
    # getting query
    query = event['body']

    # getting parameter
    rf = query['rf']
    symbols = query['symbols']
    totalworth = query['totalworth']
    presetdate = query['presetdate']
    estimating_startdate = query['estimating_startdate']
    estimating_enddate = query['estimating_enddate']
    riskcoef = query.get('riskcoef', 0.3)
    homogencoef = query.get('homogencoef', 0.1)
    V = query.get('V', 10.0)
    index = query.get('index', 'DJI')
    call_wrapper = False
    if 'email' in query:
        assert 'sender_email' in query
        assert 'filebasename' in query
        call_wrapper = True
    print('call wrapper? {}'.format(call_wrapper))
    query['riskcoef'] = riskcoef
    query['homogencoef'] = homogencoef

    logging.info('Portfolio Optimization Using Modern Portfolio Theory (MPT)')
    logging.info('Symbols: {}'.format(', '.join(symbols)))
    logging.info('Total worth: {:.2f}'.format(totalworth))
    logging.info('Date: {}'.format(presetdate))
    logging.info('Estimating start date: {}'.format(estimating_startdate))
    logging.info('Estimating end date: {}'.format(estimating_enddate))
    logging.info('Risk coefficient: {}'.format(riskcoef))
    logging.info('Homogeneity coefficient: {}'.format(homogencoef))
    logging.info('V: {}'.format(V))

    # Optimization
    starttime = time.time()
    optimized_portfolio = get_optimized_portfolio_on_mpt_entropy_costfunction(
        rf,
        symbols,
        totalworth,
        presetdate,
        estimating_startdate,
        estimating_enddate,
        riskcoef,
        homogencoef,
        V=V,
        lazy=False)
    endtime = time.time()

    portfolio_summary = optimized_portfolio.portfolio_summary
    corr = portfolio_summary['correlation']
    portfolio_summary['correlation'] = [[
        corr[i, j] for j in range(corr.shape[1])
    ] for i in range(corr.shape[0])]
    event['portfolio'] = portfolio_summary
    event['symbols_nbshares'] = optimized_portfolio.symbols_nbshares
    event['runtime'] = endtime - starttime

    # calculate dynamic portfolio
    dynport = DynamicPortfolioWithDividends(
        optimized_portfolio.symbols_nbshares, estimating_startdate)
    df = dynport.get_portfolio_values_overtime(estimating_startdate,
                                               estimating_enddate)
    indexdf = get_yahoofinance_data(index, estimating_startdate,
                                    estimating_enddate)
    indexdf['TimeStamp'] = indexdf['TimeStamp'].map(
        lambda item: datetime.strftime(item, '%Y-%m-%d'))
    indexdf.index = list(indexdf['TimeStamp'])
    df = df.join(indexdf, on='TimeStamp', how='left', rsuffix='2')
    df['Close'] = df['Close'].ffill()
    timestamps = np.array(df['TimeStamp'], dtype='datetime64[s]')
    prices = np.array(df['value'])
    r, sigma = fit_BlackScholesMerton_model(timestamps, prices)
    downside_risk = estimate_downside_risk(timestamps, prices, 0.)
    upside_risk = estimate_upside_risk(timestamps, prices, 0.)
    beta = estimate_beta(timestamps, prices, np.array(df['Close']))
    event['estimates'] = {
        'r': float(r),
        'sigma': float(sigma),
        'downside_risk': float(downside_risk),
        'upside_risk': float(upside_risk),
        'beta': float(beta) if beta is not None else None
    }

    if call_wrapper:
        print('Sending e-mail')
        lambda_client = boto3.client('lambda')
        lambda_client.invoke(
            FunctionName=
            'arn:aws:lambda:us-east-1:409029738116:function:financial-portfolio-mpt-wrapper',
            InvocationType='Event',
            Payload=json.dumps({
                'body':
                json.dumps({
                    'query': query,
                    'result': {
                        'portfolio': event['portfolio'],
                        'symbols_nbshares': event['symbols_nbshares'],
                        'runtime': event['runtime']
                    },
                    'estimates': {
                        'r': float(r),
                        'sigma': float(sigma),
                        'downside_risk': float(downside_risk),
                        'upside_risk': float(upside_risk),
                        'beta': float(beta) if beta is not None else None
                    }
                })
            }))

    # reference of a lambda output to API gateway: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
    req_res = {
        'isBase64Encoded': False,
        'statusCode': 200,
        # 'headers': {'Content-Type': 'application/json'},
        'body': json.dumps(event)
    }
    return req_res