def compute_underlying_security(portfolios, tracks, spots, portfolio, operation, inner_security, key_date, work_date=None): portfolio_id = str(portfolio.id) inner_container = SecurityContainer.objects.get(id=inner_security) if not tracks.has_key(inner_security): track = get_main_track_content(inner_container) tracks[inner_security] = track value = get_closest_value(tracks[inner_security], operation.value_date if work_date==None else work_date) if value==None: LOGGER.error("No NAV available for " + inner_container.name + " as of " + str(from_epoch(long(key_date)))) return None divisor = get_price_divisor(inner_container) portfolios[portfolio_id][key_date][inner_security]['price'] = value['value'] portfolios[portfolio_id][key_date][inner_security]['price_divisor'] = divisor spot_pf = 1.0 if inner_container.currency.short_name!=portfolio.currency.short_name and (not spots.has_key(inner_container.currency.short_name) or not spots[inner_container.currency.short_name].has_key(portfolio.currency.short_name)): spot_track = get_exchange_rate(inner_container.currency.short_name, portfolio.currency.short_name) if not spots.has_key(inner_container.currency.short_name): spots[inner_container.currency.short_name] = {} spots[inner_container.currency.short_name][portfolio.currency.short_name] = spot_track if inner_container.currency.short_name!=portfolio.currency.short_name and spots.has_key(inner_container.currency.short_name) and spots[inner_container.currency.short_name].has_key(portfolio.currency.short_name): value = get_closest_value(spots[inner_container.currency.short_name][portfolio.currency.short_name], operation.value_date if work_date==None else work_date) if value!=None: spot_pf = value['value'] else: LOGGER.error("No SPOT available for " + inner_container.currency.short_name + '/' + portfolio.currency.short_name + " as of " + str(from_epoch(long(key_date)))) return None portfolios[portfolio_id][key_date][inner_security]['price_pf'] = portfolios[portfolio_id][key_date][inner_security]['price'] * spot_pf portfolios[portfolio_id][key_date][inner_security]['price_pf_divisor'] = portfolios[portfolio_id][key_date][inner_security]['price'] * spot_pf / divisor portfolios[portfolio_id][key_date][inner_security]['spot_pf'] = spot_pf portfolios[portfolio_id][key_date][inner_security]['price_date'] = value['date'].strftime('%Y-%m-%d')
def compute_account_details(portfolio, operation, spots, accounts_history, current_account_key, previous_date, key_date, is_source, target_used): if not accounts_history.has_key(current_account_key): accounts_history[current_account_key] = {} if previous_date.has_key(current_account_key): accounts_history[current_account_key][key_date] = copy.deepcopy(accounts_history[current_account_key][previous_date[current_account_key]]) if key_date!=previous_date[current_account_key]: accounts_history[current_account_key][key_date]['fx_pnl'] = 0.0 accounts_history[current_account_key][key_date]['mvt_pnl'] = 0.0 accounts_history[current_account_key][key_date]['mvt_no_pnl'] = 0.0 accounts_history[current_account_key][key_date]['mvt_pnl_pf'] = 0.0 accounts_history[current_account_key][key_date]['mvt_no_pnl_pf'] = 0.0 else: accounts_history[current_account_key][key_date] = {'assets': 0.0, 'assets_pf': 0.0,'mvt_pnl': 0.0, 'mvt_no_pnl': 0.0, 'mvt_pnl_pf': 0.0, 'mvt_no_pnl_pf': 0.0} spot_pf = 1.0 if is_source: wrk_currency = operation.source.currency.short_name else: wrk_currency = operation.target.currency.short_name if wrk_currency!=portfolio.currency.short_name and not spots.has_key(wrk_currency): spot_track = get_exchange_rate(wrk_currency, portfolio.currency.short_name) if not spots.has_key(wrk_currency): spots[wrk_currency] = {} spots[wrk_currency][portfolio.currency.short_name] = spot_track if wrk_currency!=portfolio.currency.short_name and spots.has_key(wrk_currency) and spots[wrk_currency].has_key(portfolio.currency.short_name): value = get_closest_value(spots[wrk_currency][portfolio.currency.short_name], operation.value_date) if value!=None: spot_pf = value['value'] if is_source: multiplier = -1.0 if target_used or operation.operation_type.identifier in ['OPE_TYPE_BUY', 'OPE_TYPE_BUY_FOP'] else 1.0 else: multiplier = operation.spot if operation.spot!=None else 1.0 computed_amount = operation.amount * multiplier accounts_history[current_account_key][key_date]['assets'] += computed_amount accounts_history[current_account_key][key_date]['assets_pf'] = accounts_history[current_account_key][key_date]['assets'] * spot_pf accounts_history[current_account_key][key_date]['spot_pf'] = spot_pf if operation.operation_type.identifier not in ['OPE_TYPE_BUY', 'OPE_TYPE_SELL', 'OPE_TYPE_BUY_FOP', 'OPE_TYPE_SELL_FOP']: operation.source = get_effective_instance(operation.source) operation.target = get_effective_instance(operation.target) if (operation.source==None or (operation.source.type.identifier=='CONT_ACCOUNT' and not operation.source.account_type.identifier=='ACC_FORWARD')) and (operation.target==None or (operation.target.type.identifier=='CONT_ACCOUNT' and not operation.target.account_type.identifier=='ACC_FORWARD')): accounts_history[current_account_key][key_date]['mvt_pnl' if operation.operation_type.identifier in ['OPE_TYPE_FEES','OPE_TYPE_ACCRUED_PAYMENT','OPE_TYPE_COUPON', 'OPE_TYPE_DIVIDEND'] else 'mvt_no_pnl'] += computed_amount accounts_history[current_account_key][key_date]['mvt_pnl_pf' if operation.operation_type.identifier in ['OPE_TYPE_FEES','OPE_TYPE_ACCRUED_PAYMENT','OPE_TYPE_COUPON', 'OPE_TYPE_DIVIDEND'] else 'mvt_no_pnl_pf'] += computed_amount * spot_pf previous_date[current_account_key] = key_date previous_date[current_account_key] = key_date
def compute_positions(container=None): LOGGER.info("Start computing securities positions") if container==None: all_operations = FinancialOperation.objects.filter(operation_type__identifier__in=['OPE_TYPE_BUY','OPE_TYPE_SELL','OPE_TYPE_BUY_FOP','OPE_TYPE_SELL_FOP']).order_by('value_date') else: accounts = container.accounts.all() accounts_ids = [account.id for account in accounts] all_operations = FinancialOperation.objects.filter(Q(repository__id__in=accounts_ids) | Q(source__id__in=accounts_ids) | Q(target__id__in=accounts_ids), operation_type__identifier__in=['OPE_TYPE_BUY','OPE_TYPE_SELL','OPE_TYPE_BUY_FOP','OPE_TYPE_SELL_FOP']).order_by('value_date') tracks = {} spots = {} portfolios = {} securities = {} previous_date = {} for operation in all_operations: LOGGER.info(operation.name) portfolio = PortfolioContainer.objects.filter(accounts__id=operation.repository.id) if portfolio.exists(): portfolio = portfolio[0] else: LOGGER.error("No portfolio associated to account") continue key_date = str(epoch_time(operation.value_date)) security_id = str(operation.target.id) portfolio_id = str(portfolio.id) if not securities.has_key(security_id): securities[security_id] = {} if not portfolios.has_key(portfolio_id): portfolios[portfolio_id] = {} if previous_date.has_key(security_id): securities[security_id][key_date] = copy.deepcopy(securities[security_id][previous_date[security_id]]) if not securities[security_id].has_key(key_date): securities[security_id][key_date] = {'total': 0.0, 'name': operation.target.short_name, 'id': operation.target.id, 'type': operation.target.type.identifier} if not portfolios[portfolio_id].has_key(key_date): portfolios[portfolio_id][key_date] = {} if not securities[security_id][key_date].has_key(portfolio_id): securities[security_id][key_date][portfolio_id] = 0.0 securities[security_id][key_date][portfolio_id] = securities[security_id][key_date][portfolio_id] + (operation.quantity * (1.0 if operation.operation_type.identifier in ['OPE_TYPE_BUY', 'OPE_TYPE_BUY_FOP'] else -1.0)) securities[security_id][key_date]['total'] = securities[security_id][key_date]['total'] + (operation.quantity * (1.0 if operation.operation_type.identifier in ['OPE_TYPE_BUY', 'OPE_TYPE_BUY_FOP'] else -1.0)) if previous_date.has_key(portfolio_id): portfolios[portfolio_id][key_date] = copy.deepcopy(portfolios[portfolio_id][previous_date[portfolio_id]]) if previous_date[portfolio_id]!=key_date: if portfolios[portfolio_id][key_date].has_key('increase'): del portfolios[portfolio_id][key_date]['increase'] if portfolios[portfolio_id][key_date].has_key('decrease'): del portfolios[portfolio_id][key_date]['decrease'] if portfolios[portfolio_id][key_date].has_key('increase_fop'): del portfolios[portfolio_id][key_date]['increase_fop'] if portfolios[portfolio_id][key_date].has_key('decrease_fop'): del portfolios[portfolio_id][key_date]['decrease_fop'] if not portfolios[portfolio_id][key_date].has_key(security_id): portfolios[portfolio_id][key_date][security_id] = {'total': 0.0, 'name': operation.target.short_name, 'id': operation.target.id, 'type': operation.target.type.identifier, 'price': 0.0, 'price_pf': 0.0, 'price_date': None, 'buy_price': 0.0, 'buy_spot': 1.0} if not portfolios[portfolio_id][key_date].has_key('increase'): portfolios[portfolio_id][key_date]['increase'] = {'portfolio': 0.0} if not portfolios[portfolio_id][key_date].has_key('decrease'): portfolios[portfolio_id][key_date]['decrease'] = {'portfolio': 0.0} if not portfolios[portfolio_id][key_date].has_key('increase_fop'): portfolios[portfolio_id][key_date]['increase_fop'] = {'portfolio': 0.0} if not portfolios[portfolio_id][key_date].has_key('decrease_fop'): portfolios[portfolio_id][key_date]['decrease_fop'] = {'portfolio': 0.0} computed_amount = operation.quantity * (1.0 if operation.operation_type.identifier in ['OPE_TYPE_BUY', 'OPE_TYPE_BUY_FOP'] else -1.0) if (portfolios[portfolio_id][key_date][security_id]['total'] + computed_amount)!=0.0: portfolios[portfolio_id][key_date][security_id]['buy_price'] = computed_amount * (operation.price if operation.price!=None else 0.0) + portfolios[portfolio_id][key_date][security_id]['buy_price'] * portfolios[portfolio_id][key_date][security_id]['total'] portfolios[portfolio_id][key_date][security_id]['buy_price'] = portfolios[portfolio_id][key_date][security_id]['buy_price']/(portfolios[portfolio_id][key_date][security_id]['total'] + computed_amount) portfolios[portfolio_id][key_date][security_id]['buy_spot'] = operation.spot if operation.spot!=None else 1.0 portfolios[portfolio_id][key_date][security_id]['total'] += computed_amount portfolio_movement = portfolios[portfolio_id][key_date]['increase' if operation.operation_type.identifier in ['OPE_TYPE_BUY', 'OPE_TYPE_BUY_FOP'] else 'decrease'] portfolio_movement_fop = portfolios[portfolio_id][key_date]['increase_fop' if operation.operation_type.identifier in ['OPE_TYPE_BUY', 'OPE_TYPE_BUY_FOP'] else 'decrease_fop'] if not portfolio_movement.has_key(operation.target.currency.short_name): portfolio_movement[operation.target.currency.short_name] = 0.0 if not portfolio_movement_fop.has_key(operation.target.currency.short_name): portfolio_movement_fop[operation.target.currency.short_name] = 0.0 spot_pf = 1.0 if operation.target.currency.short_name!=portfolio.currency.short_name and (not spots.has_key(operation.target.currency.short_name) or not spots[operation.target.currency.short_name].has_key(portfolio.currency.short_name)): spot_track = get_exchange_rate(operation.target.currency.short_name, portfolio.currency.short_name) if not spots.has_key(operation.target.currency.short_name): spots[operation.target.currency.short_name] = {} spots[operation.target.currency.short_name][portfolio.currency.short_name] = spot_track if operation.target.currency.short_name!=portfolio.currency.short_name and spots.has_key(operation.target.currency.short_name) and spots[operation.target.currency.short_name].has_key(portfolio.currency.short_name): value = get_closest_value(spots[operation.target.currency.short_name][portfolio.currency.short_name], operation.value_date) if value!=None: spot_pf = value['value'] portfolios[portfolio_id][key_date][security_id]['buy_spot'] = spot_pf portfolio_movement[operation.target.currency.short_name] += operation.amount portfolio_movement['portfolio'] += operation.amount * spot_pf portfolio_movement_fop[operation.target.currency.short_name] += operation.amount if operation.operation_type.identifier in ['OPE_TYPE_SELL_FOP', 'OPE_TYPE_BUY_FOP'] else 0.0 portfolio_movement_fop['portfolio'] += (operation.amount if operation.operation_type.identifier in ['OPE_TYPE_SELL_FOP', 'OPE_TYPE_BUY_FOP'] else 0.0) * spot_pf for inner_security in portfolios[portfolio_id][key_date].keys(): if inner_security not in ['increase', 'decrease', 'increase_fop', 'decrease_fop']: compute_underlying_security(portfolios, tracks, spots, portfolio, operation, inner_security, key_date) previous_date[portfolio_id] = key_date previous_date[security_id] = key_date LOGGER.info("Completing securities positions") # Complete for portfolio_id in portfolios: movements = sorted(portfolios[portfolio_id].keys(), reverse=True) portfolio = PortfolioContainer.objects.get(id=portfolio_id) start_date = portfolio.inception_date if start_date==None: start_date = datetime.date(2014,1,1) today = datetime.date.today() while start_date<today: work_date = dt.combine(start_date, dt.min.time()) key_date = str(epoch_time(work_date)) for position_date in movements: if key_date>=position_date: break position_date = None if position_date!=None and key_date!=position_date: portfolios[portfolio_id][key_date] = copy.deepcopy(portfolios[portfolio_id][position_date]) if portfolios[portfolio_id][key_date].has_key('increase'): del portfolios[portfolio_id][key_date]['increase'] if portfolios[portfolio_id][key_date].has_key('decrease'): del portfolios[portfolio_id][key_date]['decrease'] if portfolios[portfolio_id][key_date].has_key('increase_fop'): del portfolios[portfolio_id][key_date]['increase_fop'] if portfolios[portfolio_id][key_date].has_key('decrease_fop'): del portfolios[portfolio_id][key_date]['decrease_fop'] for inner_security in portfolios[portfolio_id][key_date].keys(): if portfolios[portfolio_id][key_date][inner_security]['total']!=0.0: compute_underlying_security(portfolios, tracks, spots, portfolio, operation, inner_security, key_date, work_date) else: del portfolios[portfolio_id][key_date][inner_security] start_date = dates.AddDay(start_date, 1) LOGGER.info("Securities positions computed") set_positions_portfolios(portfolios) LOGGER.info("Securities positions (portfolio view) stored") set_positions_securities(securities) LOGGER.info("Securities positions (securities view) stored")
def compute_accounts(container=None): LOGGER.info("Start computing accounts positions") spots = {} if container==None: all_operations = FinancialOperation.objects.filter(~Q(operation_type__identifier__in=['OPE_TYPE_BUY_FOP', 'OPE_TYPE_SELL_FOP']), Q(status__identifier__in=['OPE_STATUS_EXECUTED','OPE_STATUS_CONFIRMED'])).order_by('value_date') else: accounts = container.accounts.all() accounts_ids = [account.id for account in accounts] all_operations = FinancialOperation.objects.filter(~Q(operation_type__identifier__in=['OPE_TYPE_BUY_FOP', 'OPE_TYPE_SELL_FOP']), Q(repository__id__in=accounts_ids) | Q(source__id__in=accounts_ids) | Q(target__id__in=accounts_ids), Q(status__identifier__in=['OPE_STATUS_EXECUTED','OPE_STATUS_CONFIRMED'])).order_by('value_date') accounts_history = {} previous_date = {} for operation in all_operations: target_account_used = False source_account_used = True try: portfolio = PortfolioContainer.objects.filter(accounts__id=operation.source.id) source_key = str(operation.source.id) except: source_account_used = False portfolio = PortfolioContainer.objects.filter(accounts__id=operation.target.id) if portfolio.exists(): portfolio = portfolio[0] key_date = str(epoch_time(operation.value_date)) if operation.target!=None and operation.operation_type.identifier not in ['OPE_TYPE_BUY', 'OPE_TYPE_SELL', 'OPE_TYPE_BUY_FOP', 'OPE_TYPE_SELL_FOP', 'OPE_TYPE_DIVIDEND', 'OPE_TYPE_COUPON']: target_key = str(operation.target.id) if not accounts_history.has_key(target_key): accounts_history[target_key] = {} target_account_used = True if source_account_used: compute_account_details(portfolio, operation, spots, accounts_history, source_key, previous_date, key_date, True, target_account_used) if target_account_used: compute_account_details(portfolio, operation, spots, accounts_history, target_key, previous_date, key_date, False, target_account_used) else: LOGGER.error("No portfolio associated to account") continue LOGGER.info("Completing accounts positions") # Complete for account_id in accounts_history.keys(): portfolio = PortfolioContainer.objects.filter(accounts__id=account_id) account = AccountContainer.objects.get(id=account_id) portfolio = portfolio[0] start_date = portfolio.inception_date if start_date==None: start_date = datetime.date(2014,1,1) today = datetime.date.today() movements = sorted(accounts_history[account_id].keys(), reverse=True) while start_date<today: work_date = dt.combine(start_date, dt.min.time()) key_date = str(epoch_time(work_date)) for account_date in movements: if key_date>=account_date: break account_date = None if account_date!=None and key_date!=account_date: spot_pf = 1.0 wrk_currency = account.currency.short_name if wrk_currency!=portfolio.currency.short_name and not spots.has_key(wrk_currency): spot_track = get_exchange_rate(wrk_currency, portfolio.currency.short_name) if not spots.has_key(wrk_currency): spots[wrk_currency] = {} spots[wrk_currency][portfolio.currency.short_name] = spot_track if wrk_currency!=portfolio.currency.short_name and spots.has_key(wrk_currency) and spots[wrk_currency].has_key(portfolio.currency.short_name): value = get_closest_value(spots[wrk_currency][portfolio.currency.short_name], work_date) if value!=None: spot_pf = value['value'] accounts_history[account_id][key_date] = copy.deepcopy(accounts_history[account_id][account_date]) accounts_history[account_id][key_date]['assets_pf'] = accounts_history[account_id][key_date]['assets'] * spot_pf accounts_history[account_id][key_date]['mvt_no_pnl_pf'] = 0.0 accounts_history[account_id][key_date]['mvt_pnl_pf'] = 0.0 accounts_history[account_id][key_date]['mvt_no_pnl'] = 0.0 accounts_history[account_id][key_date]['mvt_pnl'] = 0.0 accounts_history[account_id][key_date]['spot_pf'] = spot_pf start_date = dates.AddDay(start_date, 1) LOGGER.info("Accounts positions computed") set_accounts_history(accounts_history) LOGGER.info("Accounts positions stored")