Exemple #1
0
def portfolio_composition():
    '''
    Returns a list of aggregations (e.g. geography, sector) and their portfolio value per member currently in dollar value terms.
    '''
    if request.method == 'POST':
        req = request.get_json(silent=True)
        portfolio = investmentportfolio.Get_Portfolio_Holdings(
            req['portfolio'], False)['holdings']  # client portfolio
        portfolio = [item['holdings'] for item in portfolio
                     ]  #since we loaded the data in chunks originally
        portfolio = [item for sublist in portfolio
                     for item in sublist]  #flatten the list'
        aggregations = req["aggregations"]  # aggregations to compute

    NAV = sum(
        float(item['quantity']) * float(item['PRICE']) for item in portfolio)
    universe = get_expanded_universe(portfolio)
    exposures = {"NAV": NAV}
    for a in aggregations:
        values = {}
        #get unique entries for the given aggregation (keep an eye out for python2 --> 3 quirks)
        unique_a = {item[a]: item[a] for item in universe}.values()
        for u in unique_a:
            values[u] = sum(
                [item['portfolio_value'] for item in universe if item[a] == u])
        exposures[a] = values

    return Response(json.dumps(exposures), mimetype='application/json')
Exemple #2
0
def parse_universe():
    '''
    Extracts the various types of constraints from the instrument universe portfolio holdings data.
    '''
    constraints = {
        'hard_constraints': [],
        'esg_constraints': [],
        'allocation_constraints': []
    }

    #Get instrument universe - look at first holding tags (since they're all the same)
    iu = investmentportfolio.Get_Portfolio_Holdings('instrument_universe')['holdings'][0]['holdings']['holdings']

    #iterate through headers to figure out what types of constraints exist within the data.
    for key,value in iu[0].items():
        try:
            c_type,c_desc = key.split('_')
            #hard constraints start with 'has_'
            if c_type == 'has':
                constraints['hard_constraints'].append({'type':key,'description':'Any company with significant business operations that deal with ' + str(c_desc) + '.'})
            #esg constraints start with 'esg_'
            if c_type == 'esg':
                constraints['esg_constraints'].append({'type':key,'description':'ESG ranking for a given company\'s ' + str(c_desc) + ' score.'})
        except:
            #allocation constraints have no '_'. Here we need to serve up all possible values from the data to populate the UI.
            if key not in ['instrumentId','CUSIP','asset','Price']:
                enumeration = list(set([row[key] for row in iu]))
                constraints['allocation_constraints'].append({'values':enumeration,'type':key,'description':'The ' + str(key) + ' of the security.'})
    return constraints
Exemple #3
0
def search(portfolio,security):
    '''
    Returns details around the true presence of a given security [by ticker for now] in a portfolio.
    '''
    if request.method == 'POST':
        req = request.get_json(silent=True)
        portfolio = req["portfolio"]
        security = req["security"] # security to check

    portfolio = investmentportfolio.Get_Portfolio_Holdings(portfolio,False)['holdings'] # client portfolio
    portfolio = [item['holdings'] for item in portfolio] #since we loaded the data in chunks originally
    portfolio = [item for sublist in portfolio for item in sublist] #flatten the list'


    NAV = sum(float(item['quantity'])*float(item['PRICE']) for item in portfolio)
    universe = get_expanded_universe(portfolio)
    exposures = {"NAV":NAV}
    #get unique entries for the given aggregation (keep an eye out for python3 quirks)
    securities = [item for item in universe if item['TICKER']==security]
    #get esg data from the first instance (since they theoretically should all be the same for the same security)
    esg_data = {}
    price = sum(float(item['PRICE']) for item in securities)
    for key,value in securities[0].items():
        if 'esg_' in key:
            esg_data[key] = value

    exposures = {
        "NAV":NAV,
        "security":security,
        "price": price,
        "direct":sum([item['portfolio_value'] for item in securities if item['user_portfolio'] == True]),
        "indirect":sum([item['portfolio_value'] for item in securities if item['user_portfolio'] == False]),
        "esg":esg_data
    }
    return Response(json.dumps(exposures), mimetype='application/json')
Exemple #4
0
def get_expanded_universe(portfolio):
    #portfolio object as input
    universe = portfolio
    for p in portfolio:
        p.update({'portfolio_value':float(p['quantity'])*float(p['PRICE']),'user_portfolio':True})

    look_throughs = [item["TICKER"] for item in portfolio if item["HAS_LOOKTHROUGH"] == 'TRUE']
    for l in look_throughs:
        #Get fund's NAV from user portfolio (that's where the data lives) and our exposure to that fund (in $)
        fund_NAV = [float(item['FUND_NAV']) for item in portfolio if item['TICKER'] == l][0]
        exposure_to_fund = [float(item['quantity']) for item in portfolio if item['TICKER'] == l][0]

        #Get fund's individual holdings
        fund = investmentportfolio.Get_Portfolio_Holdings(l,False)['holdings']
        fund = [item['holdings'] for item in fund] #since we loaded the data in chunks originally
        fund = [item for sublist in fund for item in sublist] #flatten the list

        #calculate effective dollar exposure to each fund based on market value in parent portfolio
        for f in fund:
            #errors in csv file formats can cause issues here
            try:
                f.update({'portfolio_value':((float(f['quantity']) *float(f['PRICE']))/ fund_NAV) * exposure_to_fund,'user_portfolio':False})
            except:
                print('look at ' + str(f['name']))
        universe += fund
    return universe
Exemple #5
0
def compute_unit_tests():
    '''
    Calculates analytics for a portfolio.
    Breaks into 500 instrument chunks to comply with container constraints.
    '''
    if request.method == 'POST':
        portfolios = []
        data = json.loads(request.data)
        portfolios.append(data["portfolio"])

    #Stopwatch
    start_time = datetime.datetime.now()
    if data:
        analytics = data["analytics"]
    else:
        analytics = ['THEO/Price','THEO/Value']
    results = []

    for p in portfolios:
        portfolio_start = datetime.datetime.now()
        holdings = investmentportfolio.Get_Portfolio_Holdings(p,False)['holdings']
        #Since the payload is too large, odds are there are 500-instrument chunks added to the portfolio.
        for ph in range(0,len(holdings)):
            instruments = [row['instrumentId'] for row in holdings[ph]['holdings']]
            print("Processing " + str(p) + " portfolio segment #"+str(ph) +".")
            #send 500 IDs at a time to Instrument Analytics Service:
            #for i in instruments...
            for i in range(0,len(instruments),500):
                ids = instruments[i:i+500]
                ia = instrumentanalytics.Compute_InstrumentAnalytics(ids,analytics)
                #for j in results...
                if 'error' not in ia:
                    for j in ia:
                        r = {
                            "portfolio":p,
                            "id":j['instrument']}
                        for a in analytics:
                            r[a] = j['values'][0][a]
                        r["date"] = j['values'][0]['date']
                        h = [row for row in holdings[0]['holdings'] if j['instrument']==row['instrumentId']][0]
                        for key,value in h.items():
                            if key not in ['instrumentId']:
                                r[key] = value
                        results.append(r)
                #Debug
                if i+500<len(instruments):
                    l = i+500
                else:
                    l = len(instruments)
                print("Processed securities " + str(i) + " through " + str(l) + ". Time elapsed on this portfolio: " + str(datetime.datetime.now() - portfolio_start))

    print("Unit testing completed. Total time elapsed: " + str(datetime.datetime.now() - start_time))
    return Response(json.dumps(results), mimetype='application/json')
Exemple #6
0
def get_universe(portfolio):
    #portfolio object as input
    universe = portfolio
    look_throughs = [item["TICKER"] for item in portfolio if item["HAS_LOOKTHROUGH"] == 'TRUE']

    for l in look_throughs:
        #Get fund's individual holdings
        fund = investmentportfolio.Get_Portfolio_Holdings(l,False)['holdings']
        fund = [item['holdings'] for item in fund] #since we loaded the data in chunks originally
        fund = [item for sublist in fund for item in sublist] #flatten the list
        universe += [item for item in fund if item['TICKER'] != '']

    return universe
Exemple #7
0
def get_unit_test_delete():
    '''
    Deletes all portfolios and respective holdings that are of type 'unit test'
    '''
    portfolios = investmentportfolio.Get_Portfolios_by_Selector('type','unit test portfolio')['portfolios']
    print(portfolios)
    for p in portfolios:
        holdings = investmentportfolio.Get_Portfolio_Holdings(p['name'],False)
        # delete all holdings
        for h in holdings['holdings']:
            timestamp = h['timestamp']
            rev = h['_rev']
            investmentportfolio.Delete_Portfolio_Holdings(p['name'],timestamp,rev)
        investmentportfolio.Delete_Portfolio(p['name'],p['timestamp'],p['_rev'])
    return "Portfolios deleted successfully."
Exemple #8
0
def compute_unit_tests():
    '''
    Analyzes a video for mentions (image or audio) of companies held in your portfolio.
    '''
    if request.method == 'POST':
        portfolios = []
        data = json.loads(request.data)
        portfolios.append(data["portfolio"])

    #Stopwatch
    start_time = datetime.datetime.now()

    tickers = []
    for p in portfolios:
        portfolio_start = datetime.datetime.now()
        holdings = investmentportfolio.Get_Portfolio_Holdings(
            p, False)['holdings']
        #Since the payload is too large, odds are there are 500-instrument chunks added to the portfolio.
        for ph in range(0, len(holdings)):
            #names = [row['instrumentId'] for row in holdings[ph]['holdings']]
            print(ph)
            if len(holdings[ph]['holdings']) > 0:
                if 'Ticker' in holdings[ph]['holdings'][0]:
                    tickers = [
                        row['Ticker'] for row in holdings[ph]['holdings']
                    ]

    print(tickers)
    print("Total time elapsed: " + str(datetime.datetime.now() - start_time))

    #initiate processor
    command = "python processor/main.py"
    metadataFile = "clips/clip.metadata"
    if os.system(command) == 0:
        print('yo yo')
        with open(metadataFile, 'rb') as fp:
            metadata = pickle.load(fp)
        return json.dumps({
            'success': 'true',
            'metadata': metadata
        }), 200, {
            'ContentType': 'application/json'
        }
    else:
        print("ERROR in processor")
        return json.dumps({'success': 'fail fail ash'}), 500, {
            'ContentType': 'application/json'
        }
Exemple #9
0
def search_universe(portfolio):
    '''
    Returns the total list of securities touched by an investment portfolio (e.g. including look-throughs).
    '''
    if request.method == 'POST':
        req = request.get_json(silent=True)
        portfolio = req['portfolio']

    portfolio = investmentportfolio.Get_Portfolio_Holdings(portfolio,False)['holdings'] # client portfolio
    portfolio = [item['holdings'] for item in portfolio] #since we loaded the data in chunks originally
    portfolio = [item for sublist in portfolio for item in sublist] #flatten the list'

    universe = get_universe(portfolio)
    universe = [item['name'] + ' (' + item['TICKER'] + ')' for item in universe]

    return Response(json.dumps(universe), mimetype='application/json')
Exemple #10
0
def reset_app():
    '''
    Deletes all portfolios and respective holdings that are of type 'user_portfolio', 'benchmark', and 'root' (instrument universe)
    '''
    portfolios = investmentportfolio.Get_Portfolios_by_Selector('type','user_portfolio')['portfolios']
    portfolios += investmentportfolio.Get_Portfolios_by_Selector('type','benchmark')['portfolios']
    portfolios += investmentportfolio.Get_Portfolios_by_Selector('type','root')['portfolios']
    for p in portfolios:
        holdings = investmentportfolio.Get_Portfolio_Holdings(p['name'],False)
        # delete all holdings
        for h in holdings['holdings']:
            timestamp = h['timestamp']
            rev = h['_rev']
            investmentportfolio.Delete_Portfolio_Holdings(p['name'],timestamp,rev)
        investmentportfolio.Delete_Portfolio(p['name'],p['timestamp'],p['_rev'])
    return "Portfolios deleted successfully."
Exemple #11
0
def portfolio_analyze(portfolio):
    '''
    Returns data compatible with the Portfolio.Analyze() v1.0 front-end GUI
    '''
    if request.method == 'POST':
        req = request.get_json(silent=True)
        portfolio = req['portfolio']

    portfolio_name = portfolio  #persist name
    portfolio = investmentportfolio.Get_Portfolio_Holdings(
        portfolio, False)['holdings']  # client portfolio
    portfolio = [item['holdings'] for item in portfolio
                 ]  #since we loaded the data in chunks originally
    portfolio = [item for sublist in portfolio
                 for item in sublist]  #flatten the list'
    aggregations = [
        "geography", "Asset Class", "sector", "has_Tobacco", "has_Alcohol",
        "has_Gambling", "has_Military", "has_Fossil Fuels", "esg_Controversy",
        "esg_Environmental", "esg_Governance", "esg_Social",
        "esg_Sustainability"
    ]

    NAV = sum(
        float(item['quantity']) * float(item['PRICE']) for item in portfolio)
    response = {
        "NAV":
        NAV,
        'sin': {},
        'esg': {
            portfolio_name: {}
        },
        'search': [],  # search universe
        'portfolio': [{
            'name':
            item['name'],
            'value ($USD)': (float(item['quantity']) * float(item['PRICE'])),
            'Portfolio Contribution (%)':
            ((float(item['quantity']) * float(item['PRICE'])) / NAV) * 100,
            'Industry Sector':
            item['sector'],
            'Asset Class':
            item['Asset Class'],
            'Geography':
            item['geography']
        } for item in portfolio],
        'composition': {}
    }
    universe = get_expanded_universe(portfolio, NAV)
    response['search'] = list(
        set([item['name'] + ' (' + item['TICKER'] + ')' for item in universe]))

    #hard-coded benchmarks for now, as it's possible a user would want to make benchmark choices static...
    #benchmarks = ['IVV','HYG','LQD']
    benchmarks = ['IVV']
    for b in benchmarks:
        response['esg'][b] = {}

    #Calculate data for response
    for a in aggregations:
        #sin stocks - just need true
        if 'has_' in a:
            #we omit the parent funds in the portfolio (has_lookthrough=true) to avoid double counting the exposure
            response['sin'][a] = sum([
                item['portfolio_value'] for item in universe
                if item['HAS_LOOKTHROUGH'] == 'FALSE' if item[a] == 'TRUE'
            ])
        #esg
        elif 'esg_' in a:
            #compute average ESG for the portfolio (and benchmarks!)
            response['esg'][portfolio_name][a] = sum([
                (item['portfolio_value'] / NAV) * float(item[a])
                for item in universe if item['HAS_LOOKTHROUGH'] == 'FALSE'
            ])
        #regular aggregations
        else:
            values = {}
            #get unique entries for the given aggregation (keep an eye out for python3 quirks)
            unique_a = {item[a]: item[a] for item in universe}.values()
            for u in unique_a:
                values[u] = sum([
                    item['portfolio_value'] for item in universe
                    if item['HAS_LOOKTHROUGH'] == 'FALSE' if item[a] == u
                ])
            response['composition'][a] = values

    #get ESG data for benchmarks
    for b in benchmarks:
        portfolio = investmentportfolio.Get_Portfolio_Holdings(
            b, False)['holdings']
        portfolio = [item['holdings'] for item in portfolio
                     ]  #since we loaded the data in chunks originally
        portfolio = [item for sublist in portfolio
                     for item in sublist]  #flatten the list'
        b_NAV = sum(
            float(item['quantity']) * float(item['PRICE'])
            for item in portfolio)
        b_universe = get_expanded_universe(portfolio, b_NAV)
        for a in aggregations:
            if 'esg_' in a:
                #compute average ESG for the portfolio (and benchmarks!)
                response['esg'][b][a] = sum([
                    (item['portfolio_value'] / b_NAV) * float(item[a])
                    for item in b_universe
                    if item['HAS_LOOKTHROUGH'] == 'FALSE'
                ])
    #create world investment json for the D3 element
    create_world_json(response['composition']["geography"])

    return Response(json.dumps(response), mimetype='application/json')
Exemple #12
0
def api_analyze():
    """
    Processes the user inputs to generate the scenario csv and run simulated instrument analytics on each holding in the portfolio
    """
    output = {}

    #retrieve the json from the ajax call
    json_file = ''
    if request.method == 'POST':
        json_file = request.json
        print("post request")

    #if json_file successfully posted..
    if json_file != '':
        # check all required arguments are present:
        if not all(arg in json_file
                   for arg in ["portfolio", "riskfactor", "shockmag"]):
            print("Missing arguments in post request")
            return json.dumps({
                "status": "Error",
                "messages": "Missing arguments"
            }), 422
        portfolio = json_file["portfolio"]
        riskfactor = json_file["riskfactor"]
        shockmag = json_file["shockmag"]
        print("retreived data: " + str(portfolio) + " | " + str(riskfactor) +
              " | " + str(shockmag))

        #run Predictive Market Scenario service
        PMS_status = predictivemarketscenario.Generate_Scenario(
            riskfactor, shockmag)
        #if error in the call, return with error
        if PMS_status != 200:
            print(
                "Unable to create csv from Predictive Market Scenario service")
            return json.dumps({
                'error':
                str(PMS_status) +
                " Unable to create csv from Predictive Market Scenario service"
            })
        print("CREATED CSV")

        #get holdings data
        holdings_data = investmentportfolio.Get_Portfolio_Holdings(portfolio)

        #go through each holding in the portfolio
        asset_output = []
        for holding in holdings_data["holdings"][-1]["holdings"]:

            #call the simulatedinstrumentanalytics module
            data = simulatedinstrumentanalytics.Compute_Simulated_Analytics(
                instrument_id=holding["instrumentId"])

            #if returned as json would mean error, assign N/A, else assing the values from the list of objects
            if (type(data) is dict):
                value1 = "N/A"
                value2 = "N/A"
            else:
                value1 = data[0]["values"][0]["THEO/Price"]
                value2 = data[1]["values"][0]["THEO/Price"]

            #create obj with the output values
            asset = holding["asset"]
            instrumentId = holding["instrumentId"]
            quantity = holding["quantity"]
            companyName = holding["companyName"]
            obj = {
                'Asset': asset,
                'InstrumentId': instrumentId,
                'Quantity': quantity,
                'CompanyName': companyName,
                'BaseVal': value1,
                'NewVal': value2
            }
            #print (obj)
            asset_output.append(obj)

        #get the market_conditions as list
        if os.path.exists("output_PMS.csv"):
            market_conditions = get_market_conditions("output_PMS.csv")

        #create the output json
        output = {
            "holdingsInfo": asset_output,
            "marketConditions": market_conditions
        }

    return (json.dumps(output))
def compute_unit_tests():
    global bloomUsProcess, bloomGlobProcess, skyProcess, cnbcAfricaProcess, bloomUsNews, bloomGlobNews, skyNews, cnbcAfricaNews
    '''
    Calculates analytics for a portfolio.
    Breaks into 500 instrument chunks to comply with container constraints.
    '''
    print('Ash - Inside computing')
    if (bloomUsProcess != None):
        bloomUsProcess.terminate()
        bloomUsProcess = None
    if (bloomGlobProcess != None):
        bloomGlobProcess.terminate()
        bloomGlobProcess = None
    if (skyProcess != None):
        skyProcess.terminate()
        skyProcess = None
    if (cnbcAfricaProcess != None):
        cnbcAfricaProcess.terminate()
        cnbcAfricaProcess = None

    portfolios = []
    feeds = None
    if request.method == 'POST':
        data = json.loads(request.data)
        portfolios.append(data["portfolio"])
        feeds = data["feeds"]
        print(portfolios)
        print(feeds)
    else:
        return "API not available through GET"

    #clean
    for root, dirs, files in os.walk('clips/'):
        for filename in files:
            if filename == 'empty.txt':
                continue
            os.remove('clips/' + filename)

    if len(feeds) == 0:
        return json.dumps({
            'success': 'false',
            'metadata': 'No feeds selected'
        }), 400, {
            'ContentType': 'application/json'
        }

    #Stopwatch
    start_time = datetime.datetime.now()

    tickers = []
    for p in portfolios:
        portfolio_start = datetime.datetime.now()
        holdings = investmentportfolio.Get_Portfolio_Holdings(
            p, False)['holdings']
        #Since the payload is too large, odds are there are 500-instrument chunks added to the portfolio.
        for ph in range(0, len(holdings)):
            #names = [row['instrumentId'] for row in holdings[ph]['holdings']]
            print(ph)
            if len(holdings[ph]['holdings']) > 0:
                if 'Ticker' in holdings[ph]['holdings'][0]:
                    tickers = [
                        row['Ticker'] for row in holdings[ph]['holdings']
                    ]

    print(tickers)
    print("Total time elapsed: " + str(datetime.datetime.now() - start_time))

    #initiate processor
    metadataFile = "clips/clip.metadata"

    if bloomUsNews in feeds:
        print("Bloomberg US feed...")
        bloomUsProcess = subprocess.Popen(
            ['python', 'processor/main.py', bloomUsNews],
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT)
        t = threading.Thread(target=output_reader_bloom_us,
                             args=(bloomUsProcess, ))
        t.start()
    if bloomGlobNews in feeds:
        print("Bloomberg Global feed...")
        bloomGlobProcess = subprocess.Popen([
            'python', 'processor/main.py',
            'https://www.youtube.com/watch?v=Ga3maNZ0x0w'
        ],
                                            stdout=subprocess.PIPE,
                                            stderr=subprocess.STDOUT)
        t = threading.Thread(target=output_reader_bloom_glob,
                             args=(bloomGlobProcess, ))
        t.start()
    if skyNews in feeds:
        print("Sky News feed...")
        skyProcess = subprocess.Popen(['python', 'processor/main.py', skyNews],
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.STDOUT)
        t = threading.Thread(target=output_reader_sky, args=(skyProcess, ))
        t.start()
    if cnbcAfricaNews in feeds:
        print("CNBC Africa feed...")
        cnbcAfricaProcess = subprocess.Popen(
            ['python', 'processor/main.py', cnbcAfricaNews],
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT)
        t = threading.Thread(target=output_reader_cnbc_africa,
                             args=(cnbcAfricaProcess, ))
        t.start()

    return json.dumps({
        'success': 'true',
        'metadata': 'Processor started on feeds' + str(feeds)
    }), 200, {
        'ContentType': 'application/json'
    }
Exemple #14
0
def optimize():
    '''
    Runs an optimization calculation from a series of inputs
    1) Grabs instrument universe, user portfolio and benchmark portfolio
    2) Builds input portfolios in correct format
    3) Iterates through constraints and builds 'subportfolios' - groupings required to leverage constraints
    4) Runs the optimization and returns the set of optimal trades.
    '''
    optimization = {
        'portfolios': [],
        'objectives': [],
        'constraints': []
    }

    #retrieve the json from the ajax call
    req = ''
    if request.method == 'POST':
        req = json.loads(request.data)

    else: #for debug, a sample request
        req = {
	        'user_portfolio': {
		        'Type':'existing',
		        'Name':'my_portfolio'
            },
	        'benchmark':'Aggressive',
	        'hard_constraints':['has_tobacco','has_military'],
	        'esg_constraints':[
		        {'type':'esg_sustainability','value':'Average'},
		        {'type':'esg_environmental','value':'High'}
	        ],
	        'allocation_constraints':[
		        {'type':'asset-class','value':'Equity','allocation':.5,'inequality':'equal'},
		        {'type':'asset-class','value':'Corporate Bonds','allocation':.3,'inequality':'less than or equal'},
                {'type':'asset-class','value':'Government Bonds','allocation':.2,'inequality':'equal'}
            ],
            'result_requirements':[
	            {'type':'AllowShortSales','value':False},
		        {'type':'MaximumInvestmentWeight','value':.2}, #note the decimal! It's a percentage
                {'type':'CashInfusion','value':50000}
            ]
        }

    #FETCH PORTFOLIOS====================================================================================================
    #Grab user portfolio
    if req['user_portfolio'] is not None:
        try:
            user_portfolio = investmentportfolio.Get_Portfolio_Holdings(req['user_portfolio']['Name'])['holdings'][0]['holdings']['holdings']
        except:
            user_portfolio = {
                'name': 'user_portfolio',
                'type':'user_portfolio',
                'holdings':[]
            }
    else:
        user_portfolio = {
            'name': 'user_portfolio',
            'type':'user_portfolio',
            'holdings':[]
        }
    #Grab instrument universe holdings (for instrument universe definition and to grab all the meta-data)
    iu = investmentportfolio.Get_Portfolio_Holdings('instrument_universe')['holdings'][0]['holdings']['holdings']
    #Grab benchmark
    benchmark = investmentportfolio.Get_Portfolio_Holdings(req['benchmark'])['holdings'][0]['holdings']['holdings']
    #CONSTRUCT INSTRUMETN UNIVERSE, BENCHMARK and OBJECTIVE===================================================================
    #need to add position units with anything you currently hold
    tradeable_universe = {
        'name': 'Universe',
        'type':'root',
        'holdings':[]
    }
    for asset in iu:
        if req['user_portfolio']['Type'] != 'new':
            holding = [h['quantity'] for h in user_portfolio if h['instrumentId'] == asset['instrumentId']]
            if holding != []:
                tradeable_universe['holdings'].append({'asset':asset['instrumentId'],'quantity':holding[0]})
            else:
                tradeable_universe['holdings'].append({'asset':asset['instrumentId'],'quantity':0})
        else:
            tradeable_universe['holdings'].append({'asset':asset['instrumentId'],'quantity':0})
    optimization['portfolios'].append(tradeable_universe)

    #Construct benchmark portfolios - assumes benchmarks have defined quantities.
    benchmark_portfolio = {
        'name': req['benchmark'],
        'type':'benchmark',
        'holdings':[]
    }
    for b in benchmark:
        benchmark_portfolio['holdings'].append({'asset':b['instrumentId'],'quantity':b['quantity']})
    optimization['portfolios'].append(benchmark_portfolio)

    #Objective function
    optimization['objectives'] = [{
       'sense': 'minimize',
       'measure': 'variance',
       'attribute': 'return',
       'portfolio': 'Universe',
       'TargetPortfolio': req['benchmark'],
       'timestep': 30,
       'description': 'minimize tracking error squared (variance of the difference between Universe portfolio and Benchmark returns) at time 30 days'
    }]

    #HARD CONSTRAINTS====================================================================================================
    #Add sub-portfolio (how the optimization algorithm knows which asset has which property)
    for hc in req['hard_constraints']:
        #initialize the subportfolio
        if hc != None:
            subportfolio = {
                'ParentPortfolio':'Universe',
                'name':hc,
                'type':'subportfolio',
                'holdings':[]
            }
            #filter the instrument universe on things that have this property. This is easy as it's true/false.
            for asset in iu:
                if asset[hc] == 'TRUE':
                    #Figure out if the user currently holds any of the asset as the quantity needs to be adjusted
                    if req['user_portfolio']['Type'] != 'new':
                        q = [row['quantity'] for row in user_portfolio if row['instrumentId']==asset['instrumentId']]
                        if q!=[]:
                            subportfolio['holdings'].append({'asset':asset['instrumentId'],'quantity':q[0]})
                        else:
                            subportfolio['holdings'].append({'asset':asset['instrumentId'],'quantity':0})
                    else:
                        subportfolio['holdings'].append({'asset':asset['instrumentId'],'quantity':0})

            optimization['portfolios'].append(subportfolio)
            #Add constraint to list
            optimization['constraints'].append({
                'attribute':'weight',
                'portfolio':hc,
                'InPortfolio':'Universe',
                'relation':'equal',
                'constant':0.0,
                'description':'Excluding all securities which have the property ' + hc + '.'
            })

    #ESG CONSTRAINTS====================================================================================================
    #Add sub-portfolio (how the optimization algorithm knows which asset has which property)
    #Until we have a live data stream, we're taking a shortcut and making a single grouping and setting it to x%
    for esgc in req['esg_constraints']:
        #initialize the subportfolio
        subportfolio_name = esgc['value'] + '-' + esgc['type']
        subportfolio = {
            'ParentPortfolio':'Universe',
            'name':subportfolio_name,
            'type':'subportfolio',
            'holdings':[]
        }
        #filter the instrument universe on things that have this property. This is easy as it's true/false.
        for asset in iu:
            if asset[esgc['type']] == esgc['value']:
                if req['user_portfolio']['Type'] != 'new':
                    #Figure out if the user currently holds any of the asset as the quantity needs to be adjusted
                    q = [row['quantity'] for row in user_portfolio if row['instrumentId']==asset['instrumentId']]
                    if q!=[]:
                        subportfolio['holdings'].append({'asset':asset['instrumentId'],'quantity':q[0]})
                    else:
                        subportfolio['holdings'].append({'asset':asset['instrumentId'],'quantity':0})
                else:
                    subportfolio['holdings'].append({'asset':asset['instrumentId'],'quantity':0})
        optimization['portfolios'].append(subportfolio)

        #Add constraint to list
        optimization['constraints'].append({
            'attribute':'weight',
            'portfolio':subportfolio_name,
            'InPortfolio':'Universe',
            'relation':'greater-or-equal',
            'constant':0.5,
            'description':'Setting the portfolio to have an average ' + esgc['type'] + ' score of ' + esgc['value']+ '.'
        })

    #ALLOCATION CONSTRAINTS================================================================================================
    #Add sub-portfolio (how the optimization algorithm knows which asset has which property)
    for ac in req['allocation_constraints']:
        #initialize the subportfolio
        subportfolio_name = ac['type'] + '-' + ac['value']
        subportfolio = {
            'ParentPortfolio':'Universe',
            'name':subportfolio_name,
            'type':'subportfolio',
            'holdings':[]
        }
        #filter the instrument universe on things that have this property. This is easy as it's true/false.
        for asset in iu:
            if asset[ac['type']] == ac['value']:
                #Figure out if the user currently holds any of the asset as the quantity needs to be adjusted
                if req['user_portfolio']['Type'] != 'new':
                    q = [row['quantity'] for row in user_portfolio if row['instrumentId']==asset['instrumentId']]
                    if q!=[]:
                        subportfolio['holdings'].append({'asset':asset['instrumentId'],'quantity':q[0]})
                    else:
                        subportfolio['holdings'].append({'asset':asset['instrumentId'],'quantity':0})
                else:
                    subportfolio['holdings'].append({'asset':asset['instrumentId'],'quantity':0})
        optimization['portfolios'].append(subportfolio)

        #Add constraint to list
        optimization['constraints'].append({
            'attribute':'weight',
            'portfolio':subportfolio_name,
            'InPortfolio':'Universe',
            'relation':ac['inequality'],
            'constant':ac['allocation'],
            'description':'Sets the allocation to assets with a[n] ' +  str(ac['type']) + ' of ' + str(ac['value']) + ' to be ' + str(ac['inequality']) + ' to ' + str(ac['allocation']) + '.'
        })
    #RESULT REQUIREMENTS================================================================================================
    rr = req['result_requirements']
    for r in rr:
        #Short Sale Restriction
        if r['type'] == 'AllowShortSales':
            if r['value'] == 'False':
                optimization['constraints'].append({
                    'attribute':'weight',
                    'relation':'greater-or-equal',
                    'members':'Universe',
                    'constant':0,
                    'description':'no short-sales for assets in Universe portfolio'
                })

        #Maximum weight of any one position
        if r['type'] == 'MaximumInvestmentWeight':
            optimization['constraints'].append({
                'attribute':'weight',
                'relation':'less-or-equal',
                'members':'Universe',
                'constant':r['value'],
                'description':'Weight of each asset from the Universe portfolio does not exceed ' + str(r['value']*100) + '%.'
            })

        #Cash infusions
        if r['type'] == 'CashInfusion':
            optimization['constraints'].append({
                'attribute:': 'value',
                'portfolio': 'Universe',
                'cashadjust': float(r['value']),
                'description': 'cash inflow of ' + str(r['value']) +' monetary units to the Universe portfolio'})

    optimized_portfolio = portfoliooptimization.Optimize(optimization)

    #ASSEMBLE PORTFOLIO ATTRIBUTES================================================================================================
    #We tack on attributes from instrument universe for each optimized holding (oh) in the response from the instrument universe (iu)
    try:
        #only instruments involved in the before or after
        optimized_portfolio['Holdings']  = [row for row in optimized_portfolio['Holdings'] if (row['OptimizedQuantity']!=0 or row['Quantity']!=0)]
        for oh in range(0,len(optimized_portfolio['Holdings'])):
            #Name
            optimized_portfolio['Holdings'][oh]['Name'] = [row['asset'] for row in iu if row['instrumentId']==optimized_portfolio['Holdings'][oh]['Asset']][0]
            #Market Price
            optimized_portfolio['Holdings'][oh]['Price'] = [float(row['Price']) for row in iu if row['instrumentId']==optimized_portfolio['Holdings'][oh]['Asset']][0]
            #Aggregate Value
            optimized_portfolio['Holdings'][oh]['Total Value'] = optimized_portfolio['Holdings'][oh]['Price'] * optimized_portfolio['Holdings'][oh]['OptimizedQuantity']

            #hard constraints
            try:
                for x in req['hard_constraints']:
                    optimized_portfolio['Holdings'][oh][x] = [row[x] for row in iu if row['instrumentId']==optimized_portfolio['Holdings'][oh]['Asset']][0]
            except:
                pass

            #esg constraints
            try:
                for x in req['esg_constraints']:
                    optimized_portfolio['Holdings'][oh][x['type']] = [row[x['type']] for row in iu if row['instrumentId']==optimized_portfolio['Holdings'][oh]['Asset']][0]
            except:
                pass

            #allocation constraints
            try:
                for x in req['allocation_constraints']:
                    optimized_portfolio['Holdings'][oh][x['type']] = [row[x['type']] for row in iu if row['instrumentId']==optimized_portfolio['Holdings'][oh]['Asset']][0]
            except:
                pass

        return Response(json.dumps(optimized_portfolio, indent=4,sort_keys=True), mimetype='application/json')
    except:
        return Response(json.dumps(optimized_portfolio), mimetype='application/json')
def compute_unit_tests():
    '''
    Calculates analytics for a portfolio.
    Breaks into 500 instrument chunks to comply with container constraints.
    '''
    if request.method == 'POST':
        portfolios = []
        data = json.loads(request.data)
        portfolios.append(data["portfolio"])

    #Stopwatch
    start_time = datetime.datetime.now()
    if data:
        analytics = data["analytics"]
    else:
        analytics = ['Price', 'Value']
    results = []

    for p in portfolios:
        portfolio_start = datetime.datetime.now()
        holdings = investmentportfolio.Get_Portfolio_Holdings(
            p, False)['holdings']
        #Since the payload is too large, odds are there are 500-instrument chunks added to the portfolio.
        for ph in range(0, len(holdings)):

            #TEMPORARY WORKAROUND SINCE ID-TYPE not in legacy holdings...
            #Strip out "CX_" and "_XYZ" using split on underscore
            instruments = [{
                'id': row['instrumentId'].split("_")[1],
                "type": "isin"
            } for row in holdings[ph]['holdings']]
            print("Processing " + str(p) + " portfolio segment #" + str(ph) +
                  ".")
            #send 500 IDs at a time to Instrument Analytics Service:
            #for i in instruments...
            for i in range(0, len(instruments), 500):
                ids = instruments[i:i + 500]
                ia = simulated_instrument_analytics.simulate(ids, analytics)
                #for j in results...
                if 'error' not in ia:
                    for j in ia['results']:
                        r = {
                            "portfolio": p,
                            "ID": j['ID'],
                            "Currency": j["Currency"],
                            "Simulation Date": j["Simulation Date"],
                            "Name": j["Name"]
                        }
                        for a in analytics:
                            r[a] = j[a]
                        h = [
                            row for row in holdings[0]['holdings']
                            if j['ID'] in row['instrumentId']
                        ][0]  #Note: "in" is a workaround as we transition from old IDs ("CX_<id>_<XYZ>") to new ids
                        for key, value in h.items():
                            if key not in [
                                    'instrumentId', 'Currency', 'Name', 'name',
                                    'CURRENCY', 'PRICE'
                            ]:
                                r[key] = value
                        print(r)
                        results.append(r)

                print("Processed securities " + str(i) + " through " +
                      str(i + 500) + ". Time elapsed on this portfolio: " +
                      str(datetime.datetime.now() - portfolio_start))

    print("Unit testing completed. Total time elapsed: " +
          str(datetime.datetime.now() - start_time))
    return Response(json.dumps(results), mimetype='application/json')