from app.analysis.bar_space import index_at, price_in_bar_space from app.analysis.levels import Level, LevelKind, Side from app.bars.models import Timeframe MINUTE = 60 def sloped(anchor_t: int, anchor_p: float, last_t: int, last_p: float) -> Level: slope = (last_p - anchor_p) / (last_t - anchor_t) return Level( "ml", LevelKind.MANUAL, Timeframe.M1, Side.SUPPORT, 1, 1, "line", anchor_t, anchor_p, slope, None, 0, anchor_t, last_t, False, False, ) def test_index_is_linear_when_bars_are_evenly_spaced(): times = [i * MINUTE for i in range(10)] assert index_at(times, 0) == 0 assert index_at(times, 5 * MINUTE) == 5 assert index_at(times, int(2.5 * MINUTE)) == 2.5 def test_a_gap_costs_one_index_however_long_it_is(): # Two bars either side of a weekend are adjacent on screen. times = [0, MINUTE, MINUTE + 49 * 3600, MINUTE + 49 * 3600 + MINUTE] assert index_at(times, MINUTE) == 1 assert index_at(times, MINUTE + 49 * 3600) == 2 def test_line_stays_straight_in_bar_space_across_a_gap(): # Bars: ten minutes, a 49-hour weekend, then ten more. weekend = 49 * 3600 times = [i * MINUTE for i in range(10)] + [10 * MINUTE + weekend + i * MINUTE for i in range(10)] level = sloped(times[0], 100.0, times[9], 109.0) # 1 point per bar # Extending nine further bars must add nine more points, gap notwithstanding. assert price_in_bar_space(level, times, times[18]) == 118.0 # Clock-based pricing would have run away during the halt. assert level.price_at(times[18]) > 3000 def test_flat_anchors_return_the_anchor_price(): times = [i * MINUTE for i in range(5)] level = sloped(0, 100.0, MINUTE, 100.0) assert price_in_bar_space(level, times, times[4]) == 100.0