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))
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)}
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