def test_option_expiration(self): call = Option('call', TSLA, 500, datetime(2020, 12, 28)) port = Portfolio(0, {TSLA: 100}) te = TradingEngine([port]) te.sell_contract(port, call, 10) te.eval({TSLA: 400}, datetime(2020, 12, 28)) self.assertFalse(port.contracts()) self.assertEqual(0, port.collateral[TSLA])
def test_assign_put(self): put = Option('put', TSLA, 500, datetime(2020, 12, 28)) port = Portfolio(70000, {TSLA: 12, put: -1}) port.collateral[TSLA] = 100 te = TradingEngine() te.assign(port, put, -1) self.assertEqual(70_000 - 50_000, port.cash) self.assertEqual(112, port.securities[TSLA]) self.assertEqual(0, port.securities[put]) self.assertEqual(0, port.collateral[TSLA])
def test_assign_call(self): call = Option('call', TSLA, 500, datetime(2020, 12, 28)) secs = {TSLA: 100, call: -1} port = Portfolio(420, secs) port.collateral[TSLA] = 100 te = TradingEngine() te.assign(port, call, -1) self.assertEqual(420 + 50000, port.cash) self.assertEqual(0, port.securities[TSLA]) self.assertEqual(0, port.securities[call]) self.assertEqual(0, port.collateral[TSLA])
def test_exercise_put(self): put = Option('put', TSLA, 500, datetime(2020, 12, 28)) port = Portfolio(2000, {TSLA: 100}) te = TradingEngine([port]) te.buy_contract(port, put, 10) self.assertEqual(2000 - 1000, port.cash) self.assertEqual(1, port.contracts()[put]) te.eval({TSLA: 400}, datetime(2020, 12, 28)) self.assertEqual(2000 - 1000 + 50000, port.cash) self.assertEqual(0, port.securities.get(TSLA, 0)) self.assertEqual(0, port.securities[put])
def test_exercise_call(self): call = Option('call', TSLA, 500, datetime(2020, 12, 28)) port = Portfolio(51000, {}) te = TradingEngine([port]) te.buy_contract(port, call, 10) self.assertEqual(51000 - 1000, port.cash) self.assertEqual(1, port.contracts()[call]) te.eval({TSLA: 600}, datetime(2020, 12, 28)) self.assertEqual(0, port.cash) self.assertEqual(100, port.securities[TSLA]) self.assertEqual(0, port.securities[call])
def test_expire_without_close_on_expiration(self): path = Path('tests/test_data/normalized/TSLA') training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) call = Option('call', TSLA, 2800, datetime(2020, 7, 24)) portfolio = Portfolio(cash=0, securities={TSLA: 100, call: -1}) portfolio.collateral = {TSLA: 100} sim = Simulator(TSLA, portfolio, path, training) net = BuyAndHoldNet() sim.simulate(net, datetime(2020, 7, 23), datetime(2020, 8, 3)) self.assertEqual(0, portfolio.securities.get(call, 0))
def test_expire_and_assign(self): call = Option('call', TSLA, 500, datetime(2020, 12, 28)) port = Portfolio(0, {TSLA: 100}) te = TradingEngine([port]) te.sell_contract(port, call, 10) te.eval({TSLA: 400}, datetime(2020, 12, 28)) call = Option('call', TSLA, 500, datetime(2021, 1, 15)) te.sell_contract(port, call, 5) te.eval({TSLA: 600}, datetime(2021, 1, 15)) self.assertEqual(1000 + 500 + 50000, port.cash) self.assertEqual(0, port.securities[TSLA]) self.assertEqual(0, port.contracts()[call])
def test_sell_too_many_contracts(self): call = Option('call', TSLA, 500, datetime(2020, 12, 28)) port = Portfolio(0, {TSLA: 100}) te = TradingEngine([port]) te.sell_contract(port, call, 10) self.assertRaises(Exception, te.sell_contract, port, call, 10)
def test_release_collateral(self): call = Option('call', TSLA, 500, datetime(2020, 12, 28)) port = Portfolio(50000, {TSLA: 100}) te = TradingEngine([port]) # sell a contract to start, putting up 100 shares as collateral te.sell_contract(port, call, 10) self.assertEqual(-1, port.securities[call]) self.assertEqual(100, port.collateral[TSLA]) # buy back the contract, eliminating the obligation te.buy_contract(port, call, 10) self.assertEqual(0, port.securities[call]) self.assertEqual(0, port.collateral[TSLA]) # go long instead, purchasing a call te.buy_contract(port, call, 10) self.assertEqual(1, port.securities[call]) self.assertEqual(0, port.collateral[TSLA]) # close that long call te.sell_contract(port, call, 10) self.assertEqual(0, port.securities[call]) self.assertEqual(0, port.collateral[TSLA]) # sell an option to go short again te.sell_contract(port, call, 10) self.assertEqual(-1, port.securities[call]) self.assertEqual(100, port.collateral[TSLA])
def test_check_and_invoke_stocks(self): ss = StockSplitHandler(Path('tests/test_data/TSLA/splits.csv'), TSLA) p = Portfolio(securities={TSLA: 3}) ss.check_and_invoke(p, datetime(2020, 8, 31)) self.assertEqual(1, len(p.securities)) self.assertEqual(3 * 5, p.securities[TSLA])
def test_sell_contract(self): call = Option('call', TSLA, 500, datetime(2020, 12, 28)) port = Portfolio(0, {TSLA: 100}) te = TradingEngine([port]) te.sell_contract(port, call, 10) self.assertEqual(1000, port.cash) self.assertEqual(-1, port.securities[call])
def test_eval_no_security(self): call = Option('call', TSLA, 500, datetime(2020, 12, 28)) put = Option('put', TSLA, 500, datetime(2020, 12, 28)) port = Portfolio(50000, {TSLA: 100, call: 1, put: 1}) te = TradingEngine([port]) te.eval({Security('GOOG'): 650}, datetime(2020, 12, 28)) self.assertEqual(50000, port.cash) self.assertEqual(100, port.securities[TSLA])
def test_eval(self): call = Option('call', TSLA, 400, datetime(2020, 12, 28)) put = Option('put', TSLA, 420, datetime(2020, 12, 28)) port = Portfolio(50000, {TSLA: 200, call: -2, put: -2}) te = TradingEngine([port]) te.eval({TSLA: 410}, datetime(2020, 12, 28)) self.assertEqual(50000 + (40000 * 2) - (42000 * 2), port.cash) self.assertEqual(200, port.securities[TSLA])
def test_simulate_range(self): path = Path('tests/test_data/normalized/TSLA') training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) portfolio = Portfolio(cash=0, securities={TSLA: 100}) sim = Simulator(TSLA, portfolio, path, training) gen = sim._days_in_range('2020-6-1', '2020-7-31') self.assertEqual(pd.Timestamp('2020-6-2'), next(gen)['date']) self.assertEqual(36, len(list(gen)))
def test_days_in_range(self): path = Path('tests/test_data/normalized/TSLA') training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) portfolio = Portfolio(cash=0, securities={TSLA: 100}) sim = Simulator(TSLA, portfolio, path, training) # span a weekend gen = sim._days_in_range(datetime(2020, 7, 10), datetime(2020, 7, 14)) self.assertEqual(2, len(list(gen)))
def test_plot_trades(self): net = RandomNet(5) reporter = TradeReporter() path = Path('tests') / 'test_data' / 'normalized' / TSLA.symbol portfolio = Portfolio(cash=0, securities={TSLA: 100}) training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) sim = Simulator(TSLA, portfolio, path, training, reporter) dr = DateRangeFactory(training).random_date_range(90) vis.plot_trades(net, sim, dr, training, path, reporter, False)
def test_close_no_op(self): path = Path('tests/test_data/normalized/TSLA') training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) portfolio = Portfolio(cash=0, securities={TSLA: 100}) sim = Simulator(TSLA, portfolio, path, training) # no contracts to close, no-op sim._buy(None) self.assertEqual(100, portfolio.securities[TSLA])
def test_close_short_call(self): path = Path('tests/test_data/normalized/TSLA') training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) call = Option('call', TSLA, 420, datetime(2020, 7, 17)) portfolio = Portfolio(cash=133535, securities={call: -1}) sim = Simulator(TSLA, portfolio, path, training) sim._buy(datetime(2020, 7, 14)) self.assertEqual(0, portfolio.securities[call]) self.assertEqual(0, portfolio.cash)
def test_check_and_invoke_contracts(self): call = Option('call', TSLA, 420, datetime(2021, 4, 20)) call.price = 35 p = Portfolio(securities={call: -1}) ss = StockSplitHandler(Path('tests/test_data/TSLA/splits.csv'), TSLA) ss.check_and_invoke(p, datetime(2020, 8, 31)) new_call = Option('call', TSLA, 420 / 5, datetime(2021, 4, 20)) contract = next(iter(p.securities.keys())) self.assertEqual(1, len(p.securities)) self.assertEqual(-1 * 5, p.securities[new_call]) self.assertEqual(7, contract.price) self.assertEqual(420 / 5, contract.strike)
def test_calculate_fitness(self): path = Path('tests/test_data/normalized/TSLA') training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) call = Option('call', TSLA, 420, datetime(2020, 9, 11)) portfolio = Portfolio(cash=10, securities={TSLA: 100, call: -1}) sim = Simulator(TSLA, portfolio, path, training) actual = sim._calculate_fitness(0.2990607757568724, datetime(2020, 9, 8)) # 420.28 # starting cash + value of shares - call obligation - buy-and-hold value expected = 10 + (420.28 * 100) - (1.44 * 100) - (420.28 * 100) self.assertAlmostEqual(expected, actual, places=2)
def test_hold_only(self): path = Path('tests/test_data/normalized/TSLA') training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) portfolio = Portfolio(cash=0, securities={TSLA: 100}) sim = Simulator(TSLA, portfolio, path, training) net = BuyAndHoldNet() fitness = sim.simulate(net, datetime(2020, 7, 20), datetime(2020, 8, 22)) # close on 8/21 was 2049.98 # buy-and-hold is the fitness base-line self.assertAlmostEqual(0, fitness, places=3)
def run(config_file): config = neat.Config( neat.DefaultGenome, neat.DefaultReproduction, neat.DefaultSpeciesSet, neat.DefaultStagnation, config_file ) while True: checkpoint = sorted(glob('neat-checkpoint-*'), reverse=True) if checkpoint: pop = neat.Checkpointer.restore_checkpoint(checkpoint[0]) else: pop = neat.Population(config) stats = neat.StatisticsReporter() # add a stdout reporter to show progress in terminal pop.add_reporter(neat.StdOutReporter(True)) pop.add_reporter(stats) pop.add_reporter(neat.Checkpointer(50)) winner = pop.run(eval_genomes, 50) # display the winning genome print(f"\nBest genome:\n{winner}") win_net = neat.nn.FeedForwardNetwork.create(winner, config) view = False vis.plot_stats(stats, ylog=False, view=view) vis.plot_species(stats, view=view) portfolio = Portfolio(cash=0, securities={TSLA: 100}) simulator = Simulator(TSLA, portfolio, path, training) daterange = training_daterange_factory.random_date_range(90) reporter = TradeReporter() vis.plot_trades(win_net, simulator, daterange, training, path, reporter, view=view) node_names = {0: 'Buy', 1: 'Sell', 2: 'Hold', 3: 'Delta', 4: 'Theta'} vis.draw_net(config, winner, view=view, node_names=node_names)
def test_open_short_call(self): path = Path('tests/test_data/normalized/TSLA') training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) portfolio = Portfolio(cash=0, securities={TSLA: 100}) sim = Simulator(TSLA, portfolio, path, training) sim._sell( datetime(2020, 7, 20), 0.293070701634208, # normalized close for 7/20 0.4617712204180135, # should target the 2000 strike 0.3087888191319731 # should target 8/21 expiration ) call = Option('call', TSLA, 2000, datetime(2020, 8, 21)) self.assertEqual(-1, portfolio.securities[call]) self.assertEqual(100, portfolio.securities[TSLA]) self.assertEqual(100, portfolio.collateral[TSLA]) self.assertEqual(10875, portfolio.cash)
def eval_genomes(genomes, config): # all genomes should be compared against using the same date range t_start, t_end = training_daterange_factory.random_date_range(90) c_start, c_end = cv_daterange_factory.random_date_range(90) return_dict = Manager().dict() for genome_id, genome in genomes: net = neat.nn.FeedForwardNetwork.create(genome, config) portfolio = Portfolio(cash=0, securities={TSLA: 100}) t_sim = Simulator(TSLA, portfolio, path, training) c_sim = Simulator(TSLA, portfolio, path, validation) train_p = Process(target=worker, args=('training', t_sim, net, t_start, t_end, return_dict)) validation_p = Process(target=worker, args=('validation', c_sim, net, c_start, c_end, return_dict)) train_p.start() validation_p.start() train_p.join() validation_p.join() genome.fitness = return_dict['training'] genome.cv_fitness = return_dict['validation']
def test_sell_and_get_assigned(self): path = Path('tests/test_data/normalized/TSLA') training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) portfolio = Portfolio(cash=0, securities={TSLA: 100}) sim = Simulator(TSLA, portfolio, path, training) net = SellOnceNet() # close on 8/21 was 2049.98 # direction,expiration,strike,price,iv,delta,theta,vega # call,200821,2000.0,108.75,0.4965503408681624,0.46177122041801355,0.30752325473559794,0.5241433005010039 net.theta = 0.3087888191319731 # target 8/21 expiration net.delta = 0.4617712204180135 # target 2000 strike fitness = sim.simulate(net, datetime(2020, 7, 19), datetime(2020, 8, 22)) # premium + assigned cash - buy-and-hold value expected = (108.75 * 100) + (2000 * 100) - (2049.98 * 100) self.assertAlmostEqual(expected, fitness, places=2) self.assertEqual(0, portfolio.securities[TSLA]) self.assertEqual(0, portfolio.collateral[TSLA]) self.assertEqual(10875 + 200000, portfolio.cash)
def test_sell_and_expire(self): path = Path('tests/test_data/normalized/TSLA') training = pd.read_csv(path / 'training.csv', parse_dates=['date'], date_parser=from_small_date) portfolio = Portfolio(cash=0, securities={TSLA: 100}) sim = Simulator(TSLA, portfolio, path, training) net = SellOnceNet() # close on 8/21 was 2049.98 # direction,expiration,strike,price,iv,delta,theta,vega # call,200821,2050.0,100.0,0.49691698172618826,0.4607403125936822,0.3105944110992971,0.5219995298370175 net.theta = 0.3087888191319731 # target 8/21 expiration net.delta = 0.4607403125936822 # target 2050 strike fitness = sim.simulate(net, datetime(2020, 7, 19), datetime(2020, 8, 22)) # premium + held shares value - buy-and-hold value expected = (100 * 100) + (2049.98 * 100) - (2049.98 * 100) self.assertAlmostEqual(expected, fitness, places=2) self.assertEqual(100, portfolio.securities[TSLA]) self.assertEqual(0, portfolio.collateral[TSLA]) self.assertEqual(10000, portfolio.cash)
def test_contracts(self): call = Option('call', TSLA, 500, datetime(2020, 12, 28)) p = Portfolio(0, {call: 1}) self.assertEqual(1, p.contracts()[call])
def test_stocks(self): p = Portfolio(0, {TSLA: 1}) self.assertEqual(1, p.stocks()[TSLA])