def trading_record(self, ticker, date, total_value, is_long): """ :param ticker: ticker (str) :param date: (timestamp) :param total_value: amount of money to invest in this stock (float) :param is_long: whether to long this stock or short it (bool) :return: a dict which contains trading records and change in purchasing capacity when the position is closed """ end_date_idx = self.df.index.get_loc(date) + self.period end_date = self.df.index[end_date_idx] if ticker == 'cash': record1 = TradingRecord(ticker, total_value if is_long else -total_value, date, 1) record2 = TradingRecord(ticker, -total_value if is_long else total_value, end_date, 1) return {'records': [record1, record2], 'capacity_delta': 0} enter_price = self.analyzer.stock_price(ticker, date) exit_price = self.analyzer.stock_price(ticker, end_date) position = total_value / enter_price if is_long else -total_value / enter_price record1 = TradingRecord(ticker, position, date, enter_price) record2 = TradingRecord(ticker, -position, end_date, exit_price) capacity_delta = (exit_price - enter_price) * position return { 'records': [record1, record2], 'capacity_delta': capacity_delta }
def test_backtrace_position_non_overlapping_records(self): """portfolio's position in a stock should be zero throughout the period in which that stock is not traded""" long = TradingRecord('AAPL', 3, '2010-01-20', self.analyzer.stock_price('AAPL', '2010-01-20')) short = TradingRecord('AAPL', -3, '2010-02-01', self.analyzer.stock_price('AAPL', '2010-02-01')) self.records['AAPL'].extend([long, short]) self.ts.records = self.records self.ts.backtrace() pos = self.ts.df['AAPL_pos']['2010-01-15':'2010-01-19'] self.assertListEqual(pos.tolist(), [0.0] * len(pos))
def setUpClass(cls): cls.tickers = ['AAPL', 'MSFT'] cls.analyzer = Analyzer(cls.tickers, start='2010-01-01') cls.aapl_long_3 = TradingRecord('AAPL', 3, '2010-01-05', cls.analyzer.stock_price('AAPL', '2010-01-05')) cls.aapl_short_3 = TradingRecord('AAPL', -3, '2010-01-15', cls.analyzer.stock_price('AAPL', '2010-01-15')) cls.msft_long_3 = TradingRecord('MSFT', 3, '2010-01-05', cls.analyzer.stock_price('MSFT', '2010-01-05')) cls.msft_short_3 = TradingRecord('AAPL', -3, '2010-01-15', cls.analyzer.stock_price('MSFT', '2010-01-15')) cls.records = {'AAPL':[cls.aapl_long_3, cls.aapl_short_3], 'MSFT':[cls.msft_long_3, cls.msft_short_3]} cls.analyzer_momentum = Analyzer(cls.tickers, start='2010-01-01')
def apply(self, start_date): period, holding_period = self.period, self.period # winners(date, period, n, volume_filter=False): end_date = self.df.index[-1] current_date = datetime.strptime(start_date, '%Y-%m-%d') capacity = self.initial_value while current_date < end_date: end_period_idx = self.df.index.get_loc(current_date) + self.period if end_period_idx >= self.df.shape[0]: self.records['cash'].append( TradingRecord('cash', capacity, current_date, 1)) break winners = self.analyzer.winners(current_date.strftime("%Y-%m-%d"), period, 5, False) losers = self.analyzer.losers(current_date.strftime("%Y-%m-%d"), period, 5, False) capacity_delta = 0 for s in winners: record_cap_delta = self.trading_record( s, current_date, 2 * capacity / float(len(winners)), True) self.records[s].extend(record_cap_delta['records']) capacity_delta += record_cap_delta['capacity_delta'] for s in losers: record_cap_delta = self.trading_record( s, current_date, capacity / float(len(losers)), False) self.records[s].extend(record_cap_delta['records']) capacity_delta += record_cap_delta['capacity_delta'] if not winners or not losers: cash_long = 2 * capacity if not winners else 0 cash_short = capacity if not losers else 0 cash_record = self.trading_record('cash', current_date, cash_long - cash_short, True)['records'] self.records['cash'].extend(cash_record) # recalculate purchasing power capacity += capacity_delta idx = self.df.index.get_loc(current_date) + self.period current_date = self.df.index[idx]