def show_ret_diff(dt, rdf, window = 1000, root1 = 'ZN',root2 = 'ZB', ax = plt): sym1 = utils.get_front_symbol(dt, root1) sym2 = utils.get_front_symbol(dt, root2) try: df1 = utils.load_day(dt, sym1) df2 = utils.load_day(dt, sym2) except: return a1 = rdf[rdf.DATE == int(dt.strftime('%Y%m%d'))].true_bin - 10 a2 = a1 + window ret1 = (df1.microprice.values[a1:a2] - df1.microprice.values[a1 - 10]) / float(df1.microprice.values[a1 - 10]) ret2 = (df2.microprice.values[a1:a2] - df2.microprice.values[a1 - 10]) / float(df2.microprice.values[a1 - 10]) ax.plot(ret1/ret2) #ax.plot(ret1) #ax.plot(ret2) try: ax.set_title(dt) except: ax.title(dt)
def directional_bt(rdf, stats, stats2, root = 'ZN', entry_time = 5, exit_time = 2000, go_thres = 0, size_mult= 10, ): data = {} for dt in sorted(rdf.DATE.unique()): ttt = rdf[rdf.DATE == dt] offset = ttt.true_bin.values[0] dtt = datetime.strptime(str(dt),'%Y%m%d') sym = utils.get_front_symbol(dtt, root) try: df = utils.load_day(dtt, sym, res ='0', root=root) except: continue is_buy = True a_s = ttt.a_s.values[0] if a_s < go_thres: is_buy = True elif a_s >= go_thres: is_buy = False else: continue res = utils.true_profit(df, is_buy=is_buy, size = np.abs(a_s*size_mult), num_levels = max(1,int(np.abs(a_s) / 10.0)), offset1 = offset + entry_time, offset2 = offset + exit_time, mpi= utils.get_mpi(root, dt=dtt), tick_price = utils.get_dpt(root, dt=dtt)) data[dt] = res results = {} results['data'] = data results['root'] = root results['entry_time'] = entry_time results['exit_time'] = exit_time results['go_thres'] = go_thres results['size_mult'] = size_mult return results
def detect(rdf,root='ZN', dtt='20110708', window=100, ax=plt, make_picture=True, offset = 1800): dt = datetime.strptime(str(dtt), '%Y%m%d') offset = rdf[rdf.DATE == int(dt.strftime('%Y%m%d'))]['bin'].values[0] * 10 try: sym = utils.get_front_symbol(dt, root) fine = utils.load_day(dt,sym, res='0',root=root) except: return -1 sample_vol = (fine.buy_vol + fine.sell_vol).values[offset-window:offset+window] sample_price = fine.microprice.values[offset-window:offset+window] sample_price_diff = np.diff(sample_price) fine_offset_vol = offset - window + np.argmax(sample_vol) fine_offset_price1 = offset - window + np.argmax(sample_price_diff) + 1 fine_offset_price2 = offset - window + np.argmin(sample_price_diff) + 1 fine_offset = -1 if fine_offset_price1 == fine_offset_vol or fine_offset_price2 == fine_offset_vol: fine_offset = fine_offset_vol else: vol_thres = np.max(sample_vol) / 10 for i in xrange(len(sample_vol)): if sample_vol[i] > vol_thres: fine_offset_vol = offset - window + i if fine_offset_price1 == fine_offset_vol or fine_offset_price2 == fine_offset_vol: fine_offset = fine_offset_vol break a_s = rdf[rdf.DATE == int(dtt)].a_s.values[0] if make_picture == True: ax.plot(sample_vol, '-') ax.twinx().plot(sample_price - sample_price[0], 'r-') ax.set_title( '%s %s %s %d' % (sym, dtt, fine_offset, a_s)) return fine_offset
def make_daily_returns_frame(roots, true_offset, dtt='20110708', intervals = None): dt = datetime.strptime(str(dtt), '%Y%m%d') data = [] for root in roots: root_data = [] root_data.append(dtt) root_data.append(root) sym = utils.get_front_symbol(dt, root) has_data = True try: fine = utils.load_day(dt,sym, res='0',root=root) except: has_data = False if has_data and len(fine) < 288001: has_data = False print len(fine), dt, root if has_data: for interval in intervals: root_data.append(fine.microprice.values[true_offset + interval]) else: for interval in intervals: root_data.append(0) data.append(root_data) cols = ['DATE', 'ROOT'] for interval in intervals: cols.append(interval) return pd.DataFrame(data, columns=cols)
from utils import load_day day_six_input = load_day(6, sample=False, split=False).split('\n\n') # Part 1 n = 0 for group in day_six_input: c = set.union(*(set(row) for row in group.split())) n += len(c) print(f'Part 1: {n}') # Part 2 n = 0 for group in day_six_input: c = set.intersection(*(set(row) for row in group.split())) n += len(c) print(f'Part 2: {n}')
from utils import load_day equations = load_day(18) def find_closing_parens(s, idx, n_parens=1): lookup = {'(': 1, ')': -1} while n_parens >= 1: n_parens += lookup.get(s[idx], 0) idx += 1 return idx - 1 def find_closing_space(s, idx): try: return s.index(' ', idx) except ValueError: return len(s) def to_int_or_symbol(eq): try: return int(eq) except ValueError: return eq.strip() def evaluate_equation(eq, eval_fn): idx = 0 eq_parts = [] while idx < len(eq):
from itertools import combinations from utils import load_day # Part 1 day_one_input = {int(v) for v in load_day(1)} for n in day_one_input: paired_value = 2020 - n if paired_value in day_one_input: break print('Part 1: {}'.format(n * paired_value)) # Part 2 day_one_input = [int(v) for v in load_day(1)] for combo in combinations(day_one_input, 3): if sum(combo) == 2020: break print('Part 2: {}'.format(combo[0] * combo[1] * combo[2]))
from collections import defaultdict import numpy as np from utils import load_day data = load_day(16, split=False) # Part 1 values, your_ticket, nearby_tickets = data.split('\n\n') your_ticket = np.array([int(v) for v in your_ticket.split('\n')[1].split(',')]) def str_to_range(r): return tuple(int(v) for v in r.split('-')) def find_all_ranges(values): all_ranges = {} for row in values.split('\n'): name, criteria = row.split(':') small, _, large = criteria.split() all_ranges[name] = [str_to_range(small), str_to_range(large)] return all_ranges def valid_range(v, ranges): return any(r[0] <= v <= r[1] for r in ranges) range_dict = find_all_ranges(values)
import numpy as np from utils import load_day day_3_map = load_day(3) def traverse_mountain(dx, dy, x=0, y=0): w = len(day_3_map[0]) n_trees = 0 while y < len(day_3_map): if day_3_map[y][x] == '#': n_trees += 1 x, y = (x + dx) % w, (y + dy) return n_trees # Part 1 trees = traverse_mountain(3, 1) print('Part 1: {}'.format(trees)) # Part 2 slopes = [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)] all_trees = np.prod([traverse_mountain(*s) for s in slopes]) print('Part 2: {}'.format(all_trees))
def rotate(x, y, degrees): theta = np.deg2rad(degrees) xp = x * cos(theta) - y * sin(theta) yp = x * sin(theta) + y * cos(theta) return round(xp), round(yp) dirs = { 'N': (0, 1), 'S': (0, -1), 'E': (1, 0), 'W': (-1, 0), } commands = load_day(12, sample=False) # Part 1 x, y = 0, 0 hx, hy = 1, 0 for command in commands: cmd, amt = command[0], int(command[1:]) if cmd in ('N', 'S', 'E', 'W'): dx, dy = dirs[cmd] x += dx * amt y += dy * amt elif cmd in ('L', 'R'): degrees = amt if cmd == 'L' else -amt hx, hy = rotate(hx, hy, degrees) elif cmd == 'F': x += hx * amt
import os import numpy as np from scipy.signal import convolve2d from utils import load_day photo_data = load_day(20, sample=False, split=False).split('\n\n') w = int(np.sqrt(len(photo_data))) def parse_all_photos(photo_data): photos = {} for photo in photo_data: photo_raw = photo.split('\n') photo_id = photo_raw[0].replace(':', '').split()[1] photo = np.array([ [c == '#' for c in p] for p in photo_raw[1:] ]) photos[photo_id] = photo return photos def all_orientations(photo): photos = [] for flip in [False, True]: p = photo.copy() if flip: p = np.fliplr(p) for _ in range(4):
from collections import Counter, defaultdict import numpy as np from utils import load_day day_ten_input = load_day(10, sample=False) jolts = [int(d) for d in day_ten_input] # Part 1 sort_jolts = [0] + sorted(jolts) dj = np.array(sort_jolts[1:]) - np.array(sort_jolts)[:-1] counts = Counter(dj) print(f'Part 1: {(counts[3] + 1) * counts[1]}') # Part 2 jolt_set = {0} | set(jolts) options = defaultdict(lambda: 0, {max(jolt_set): 1}) for j in sorted(sort_jolts, reverse=True): for nj in range(j - 1, j - 4, -1): if nj in jolt_set: options[nj] += options[j] print(f'Part 2: {options[0]}')
from utils import load_day day_eight_input = load_day(8, sample=False) commands = [] state_change = { 'jmp': lambda x: (int(x), 0), 'nop': lambda x: (1, 0), 'acc': lambda x: (1, int(x)), 'none': lambda x: (None, None), } instr_swap = {'jmp': 'nop', 'nop': 'jmp', 'acc': 'none'} for d in day_eight_input: instr, num = d.split() primary = state_change[instr](num) secondary = state_change[instr_swap[instr]](num) commands.append([primary, secondary]) # Part 1 line, accum = 0, 0 visited = set() while line not in visited: visited.add(line) d_line, d_acc = commands[line][0] line += d_line accum += d_acc print(f'Part 1: {accum}')
from utils import load_day def find_num_loops(key, value=1): n, subject_num = 0, 7 while value != key: value = (value * subject_num) % 20201227 n += 1 return n def transform_key(subject_num, loop_size, value=1): for _ in range(loop_size): value = (value * subject_num) % 20201227 return value door_key, card_key = load_day(25) door_key, card_key = int(door_key), int(card_key) door_loops = find_num_loops(door_key) card_loops = find_num_loops(card_key) door_enc_key = transform_key(door_key, card_loops) card_enc_key = transform_key(card_key, door_loops) assert door_enc_key == card_enc_key print(f'Part 1: {door_enc_key}')
from collections import defaultdict import numpy as np from scipy.signal import convolve2d from utils import load_day commands = load_day(24) all_tiles = defaultdict(bool) dirs = { 'ne': (1, 1), 'nw': (-1, 1), 'e': (2, 0), 'w': (-2, 0), 'se': (1, -1), 'sw': (-1, -1), } neighbor_kern = np.array([ [0, 1, 0, 1, 0], [1, 0, 0, 0, 1], [0, 1, 0, 1, 0], ]).transpose() def turn_tile(cmd): idx, pos = 0, np.array([0, 0]) while idx < len(cmd): if cmd[idx] in ('n', 's'): mv = dirs[cmd[idx:idx + 2]] idx += 2 else:
import numpy as np from scipy.signal import convolve2d from utils import load_day rows = load_day(11) mapping = {'.': 0, 'L': 1, '#': 2} seats = np.array([[mapping[c] for c in r] for r in rows]) def find_equilibrium(neighbor_fn, n_allowed=4): occupied = np.zeros_like(seats) next_round = np.array(seats) while np.abs(next_round - occupied).sum() > 0: occupied = next_round n_neighbors = neighbor_fn(occupied) filled = (n_neighbors == 0) remained = (occupied & (n_neighbors < n_allowed)) next_round = seats & (filled | remained) return next_round.sum() # Part 1 sum_kernel = np.ones((3, 3)) sum_kernel[1, 1] = 0 def find_neighbors(occupied): return convolve2d(occupied, sum_kernel, 'same')
import numpy as np from utils import load_day data = load_day(14) def mask_to_int(mask): return int(''.join(mask), 2) def bitmask(arr, c): return mask_to_int(['1' if v == c else '0' for v in arr]) # Part 1 regs = {} for row in data: reg, value = row.split(' = ') if reg == 'mask': and_mask = bitmask(value, 'X') change_mask = np.bitwise_not(and_mask) change_value = mask_to_int([v if v != 'X' else '0' for v in value]) or_mask = change_value & change_mask else: regs[reg] = (int(value) & and_mask) | or_mask print(f'Part 1: {sum(regs.values())}') # Part 2 def convert_iter_to_mask(masks, value):
from utils import load_day intro_nums = load_day(15, split=False).split(',') def play_memory_game(intro_nums, count_to): nums = {int(n): i+1 for i, n in enumerate(intro_nums[:-1])} n = int(intro_nums[-1]) for i in range(len(nums) + 1, count_to): prev_n = n n = ( i - nums[n] if n in nums else 0 ) nums[prev_n] = i return n # Part 1 n = play_memory_game(intro_nums, 2020) print(f'Part 1: {n}') # Part 2 n = play_memory_game(intro_nums, 30000000) print(f'Part 2: {n}')
import numpy as np from scipy import ndimage from utils import load_day start_board = load_day(17) def parse_initial_board(start_board, pad=6): n = len(start_board) mn = n + 2 * pad board = np.zeros((mn, mn, mn, mn)) for row in start_board: for x in range(n): for y in range(n): board[pad, pad, x + pad, y + pad] = start_board[x][y] == '#' return board def run_cube_rules(board, k, n): for i in range(n): n_neighbors = ndimage.convolve(board, k, mode='constant') remains_active = (board != 0.0) & ((n_neighbors == 2) | (n_neighbors == 3)) becomes_active = np.logical_not(board) & (n_neighbors == 3) board = (remains_active | becomes_active).astype(float) return board # Part 1 k = np.ones((3, 3, 3))
from collections import deque from itertools import combinations from utils import load_day is_sample = False day_nine_input = load_day(9, sample=is_sample) day_nine_input = [int(v) for v in day_nine_input] preamble = 5 if is_sample else 25 values = day_nine_input # Part 1 def is_valid(v, arr): return any([v == sum(p) for p in combinations(arr, 2)]) for idx in range(preamble, len(values) - 1): v = values[idx] p_arr = values[idx - preamble:idx] if not is_valid(v, p_arr): break invalid_value = v print(f'Part 1: {invalid_value}') # Part 2 current_sum = 0 low, high = (0, 0) while current_sum != invalid_value: if current_sum < invalid_value:
import re from collections import defaultdict, Counter from itertools import chain from utils import load_day foods = load_day(21, sample=False) def parse_allergen_mapping(foods): contains_mapping = defaultdict(set) all_foods = [] for food in foods: food_names, contains_names = food.replace(')', '').split('(contains ') food_names = food_names.split() all_foods.extend(food_names) for n in contains_names.split(', '): if len(contains_mapping[n]) == 0: contains_mapping[n] = set(food_names) else: contains_mapping[n] &= set(food_names) return contains_mapping, all_foods # Part 1 contains_mapping, all_foods = parse_allergen_mapping(foods) may_have_allergen = set(chain(*contains_mapping.values())) no_allergens = set(all_foods) - may_have_allergen food_counts = Counter(all_foods) no_allergen_count = sum([food_counts[f] for f in no_allergens]) print(f'Part 1: {no_allergen_count}')
import numpy as np from utils import load_day data = load_day(22, split=False).split('\n\n') p1_data = [int(c) for c in data[0].split('\n')[1:][::-1]] p2_data = [int(c) for c in data[1].split('\n')[1:][::-1]] def play_simple_game(p1_data, p2_data): p1_data, p2_data = list(p1_data), list(p2_data) while p1_data and p2_data: c1, c2 = p1_data.pop(), p2_data.pop() arr = p1_data if c1 > c2 else p2_data arr[0:0] = [min([c1, c2]), max(c1, c2)] return p1_data or p2_data def score_hand(arr): values = np.array(arr) * np.array(range(1, len(arr) + 1)) return values.sum() # Part 1 winning_hand = play_simple_game(p1_data, p2_data) print(f'Part 1: {score_hand(winning_hand)}') def hand_id(d): return ' '.join([str(v) for v in d])
from utils import load_day day_five_input = load_day(5) half_fn = lambda x, i: x[i] def half(pos, is_high): low, high = pos h = (high - low) // 2 return (high - h, high) if is_high else (low, low + h) def find_seat(part): row, col = (1, 128), (1, 8) for c in part: if c == 'F' or c == 'B': row = half(row, c == 'B') elif c == 'L' or c == 'R': col = half(col, c == 'R') return row[0] - 1, col[0] - 1 # Part 1 max_seat = 0 all_seat_ids = [] for row in day_five_input: row = find_seat(row) seat_id = row[0] * 8 + row[1] all_seat_ids.append(seat_id) max_seat = max(seat_id, max_seat)
import re from collections import defaultdict from utils import load_day day_seven_input = load_day(7, sample=False, split=True) parents = defaultdict(set) children = defaultdict(set) for row in day_seven_input: bag = re.match(r'(.+) bags contain', row).groups()[0] for count, child in re.findall(r'(\d) (.+?) bag', row): parents[child].add(bag) children[bag].add((int(count), child)) # Part 1 to_check = ['shiny gold'] valid_bags = set() while to_check: bag = to_check.pop() valid_bags.add(bag) to_check.extend(parents[bag]) print(f'Part 2: {len(valid_bags) - 1}') # Part 2 to_add = [(1, 'shiny gold')] total = 0 while to_add: p_num, bag = to_add.pop() total += p_num for c_num, child in children[bag]:
def is_valid(orig_msg, rules_dict): valid_options = [(r, orig_msg) for r in rules_dict['0']] while valid_options: rule, msg = valid_options.pop() option = rule[0] if option in ['a', 'b']: if msg[0] == option: if len(rule) == 1 and len(msg) == 1: return True elif len(rule) >= 2 and len(msg) >= 2: valid_options.append((rule[1:], msg[1:])) continue for nx in rules_dict[option]: next_option = nx + rule[1:] valid_options.append((next_option, msg)) return False rows = load_day(19, split=False) # Part 1 rules_dict, messages = parse_rules_and_messages(rows) num_valid = sum([is_valid(s, rules_dict) for s in messages]) print(f'Part 1: {num_valid}') # Part 2 rules_dict, messages = parse_rules_and_messages(rows, is_part_2=True) num_valid = sum([is_valid(s, rules_dict) for s in messages]) print(f'Part 2: {num_valid}')
return HEIGHT_IN_FN(x.replace('in', '')) else: return False def regex_match(r): return lambda x, r=r: bool(re.fullmatch(r, x)) REQUIRED_CODES = {'byr', 'iyr', 'eyr', 'hgt', 'hcl', 'ecl', 'pid'} EYE_CODES = {'amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth'} HEIGHT_CM_FN = valid_range(150, 193) HEIGHT_IN_FN = valid_range(59, 76) day_four_input = load_day(4, sample=False, split=False) # Part 1 n_valid = 0 for passport in day_four_input.split('\n\n'): codes = parse_passport(passport).keys() missing_codes = REQUIRED_CODES - set(codes) n_valid += len(missing_codes) == 0 print(f'Part 1: {n_valid}') # Part 2 IS_VALID_FNS = { 'byr': valid_range(1920, 2002),
from collections import Counter from utils import load_day # Part 1 n_correct = 0 for d in load_day(2): criteria, password = d.split(': ') valid_range, letter = criteria.split() valid_range = tuple(int(t) for t in valid_range.split('-')) pass_count = Counter(password) actual_count = pass_count[letter] if actual_count >= valid_range[0] and actual_count <= valid_range[1]: n_correct += 1 print(f'Part 1: {n_correct}') # Part 2 n_correct = 0 for d in load_day(2): criteria, password = d.split(': ') valid_range, letter = criteria.split() l, r = tuple(int(t) for t in valid_range.split('-')) if (password[l - 1] == letter) ^ (password[r - 1] == letter): n_correct += 1 print(f'Part 2: {n_correct}')