def update_holdings(self, end=None): if not self.transactions.all(): return if end is None: end = last_business_day() hlds = {} for txn in self.transactions.order_by('datetime').all(): sym = txn.security.symbol if sym not in hlds: # Transaction for a new security # find the latest holding record for this symbol # if found, the current transaction must has been processed in the past and will # be skipped below # if not found, start an empty holding record here hlds[sym] = self._get_latest_record_or_empty(txn) # convert date into pandas timestamp with business offset to automatically skip holidays hld_date = to_business_timestamp(hlds[sym].date) txn_date = to_business_timestamp(date_(txn.datetime)) if txn_date < hld_date: # already processed in the past continue elif txn_date == hld_date: # there might be multiple transactions for a day if not txn.processed: self._transact_and_save(hlds[sym], txn) else: # txn_date > hld_date # self.fill_in_gaps(hlds[sym], pd.bdate_range(start=hld_date+1, end=txn_date-1)) self.insert_holding(hlds[sym], txn_date) self._transact_and_save(hlds[sym], txn)
def update_holdings(self, end): if not self.transactions.all(): return hlds = {} for txn in self.transactions.all(): sym = txn.security.symbol if sym not in hlds: # Transaction for a new security # find the latest holding record for this symbol # if found, the current transaction must has been processed in the past and will # be skipped below # if not found, start an empty holding record here hlds[sym] = self.get_latest_record_or_empty(txn) # convert date into pandas timestamp with business offset to automatically skip holidays # note holding record is kept for every business day, so detail time of the transaction # is stripped off. hld_date = to_business_timestamp(hlds[sym].date) txn_date = to_business_timestamp(date_(txn.datetime)) if txn_date < hld_date: # already processed in the past continue elif txn_date == hld_date: # there might be multiple transactions for a day self._transact_and_save(hlds[sym], txn) else: # txn_date > hld_date self.fill_in_gaps(hlds[sym], pd.bdate_range(start=hld_date+1, end=txn_date-1)) self.insert_holding(hlds[sym], txn_date) self._transact_and_save(hlds[sym], txn) # fill the gaps between last transaction and end for sym, hld in hlds.items(): self.fill_in_gaps(hld, pd.bdate_range(start=to_business_timestamp(hld.date)+1, end=end))
def update_db(cls): last_db_date = INIT_DATE exchange = Exchange() if ExchangeRate.objects.all(): last_db_date = ExchangeRate.objects.order_by('date').last().date last_db_date = pd.Timestamp(last_db_date, offset='B')+1 for d in pd.bdate_range(start=last_db_date, end=last_business_day()): rates = exchange.historical_rates(d) for c in CURRENCY_CHOICES: if c[0] == BASE_CURRENCY: continue cls.objects.create(date=date_(d), currency=c[0], rate=exchange.exchange(1, c[0], BASE_CURRENCY, rates))
def _get_latest_record_or_empty(self, txn): try: return self.holdings.filter(security=txn.security).latest() except Holding.DoesNotExist: return Holding(security=txn.security, portfolio=self, date=date_(txn.datetime))