def get_price(s3_client: S3Client,
              s3_bucket: str,
              ticker: str,
              trading_day: arrow.arrow.Arrow,
              stack_calls: int = 0) -> Optional[float]:
    """
    Returns the adjusted close for a ticker on the date.

    If trading_day is not a valid trading day on the NYSE, the most recent
    day, up to `trading_day` is used.
    """
    stack_calls += 1
    max_stack_calls = 50
    if stack_calls > max_stack_calls:
        raise RuntimeError(
            f"stack_calls exceeded max_stack_calls: {max_stack_calls} for {ticker} on {trading_day.format('YYYY-MM-DD')}"
        )

    while not is_valid_trading_day(trading_day):
        trading_day = trading_day.shift(days=-1)

    df = get_eod_prices(s3_client, s3_bucket, trading_day)
    price = None
    try:
        price = df.loc[ticker]["adjusted_close"]
    except KeyError:
        # unable to get price for given ticker. Rewind day until we retrieve valid price
        price = get_price(s3_client, s3_bucket, ticker,
                          trading_day.shift(days=-1), stack_calls)
    return price
def calculate_lookback_window(now: arrow.arrow.Arrow, lookback_months: int) -> LookbackPeriod:
    """
    Calculate lookback period for momentum.

    start period defined as the first day of the month, 13 months ago, enabling us to get initial value to compare
    """
    start_period = now.shift(months=-lookback_months).replace(day=1)
    # end period excludes the most recent full month, (exclusive)
    end_period = now.shift(months=-1).replace(day=1)
    return LookbackPeriod(start_period, end_period)