Beyond the Crystal Ball: Perfect-Foresight Bitcoin Trading on QuantConnect

Welcome to the first blog post in a new series introducing our upcoming book, “Hands-On AI Trading with Python, QuantConnect, and AWS.”

In today’s post, we’re exploring the world of Bitcoin—an asset renowned for its volatility and even more spectacular opportunity. We often ask:

“What if we had a perfect crystal ball telling us whether BTCUSD’s price would rise tomorrow?”

Since Bitcoin captured global attention, predicting the price of BTCUSD has been a widely discussed topic. While many approaches focus on technical indicators, macro events, or AI-based price forecasting, it’s helpful to understand the best-case scenario for a trading strategy holding Bitcoin for at most one day if every daily decision (buy or sell) was correct.

Such a strategy:

  1. Buys at today’s close and sells at tomorrow’s close only if tomorrow’s price rise is significant enough to cover fees.
  2. Ignores any “guesswork” about sideways moves or partial signals—if tomorrow’s close is guaranteed to be higher than today’s by a margin above the transaction costs, we take the trade.
  3. Accumulates capital multiplicatively across all profitable days.

This approach is unrealistic in real-time trading, yet it tells us what the upper bound might be if we could reliably outsmart the market’s short-term fluctuations.

QuantConnect provides a powerful Research Environment where you can write Python code, fetch historical data instantly, and run flexible experiments. It’s an ideal sandbox to test hypothetical or advanced prototypes before turning them into complete trading algorithms.

Code: Perfect Foresight Daily Strategy

Below is a snippet you can copy-paste into a QuantConnect Research Notebook. It does the following:

  • Sorts daily closing prices for BTCUSD.
  • Iterates from day i to day i+1.
  • Checks if tomorrow’s price is sufficiently higher than today’s to cover transaction fees (e.g., 1% total).
  • If profitable, executes a hypothetical buy at today’s close and sell at tomorrow’s close, updating your capital.
  • Returns your final capital multiple and a list of trades (buy date, buy price, sell date, sell price, net return, etc.).
def perfect_foresight_daily_with_orders(prices: pd.Series, round_trip_fee_pct: float):
    """
    Simulates a perfect-foresight strategy that decides daily whether
    to buy today's close and sell tomorrow's close, if profitable after fees.
    
    This version also returns a list of all executed trades with details.
    
    Parameters
    ----------
    prices : pd.Series
        Daily closing prices, with a DateTimeIndex or similar
    round_trip_fee_pct : float
        Total transaction fee (fraction) for a buy+sell round trip.
        e.g. 0.01 => 1% total for buy+sell
    
    Returns
    -------
    final_capital : float
        Growth factor of 1 initial capital after all trades
    trades : pd.DataFrame
        A DataFrame (or list) of all trades made, with columns:
            - "BuyDate", "BuyPrice"
            - "SellDate", "SellPrice"
            - "GrossReturn"
            - "NetReturn"
            - "CapitalBefore"
            - "CapitalAfter"
    """
    capital = 1.0
    trades_list = []

    # Sort the Series chronologically just in case
    prices = prices.sort_index()
    price_values = prices.values
    price_index  = prices.index

    for i in range(len(prices) - 1):
        p_t   = price_values[i]
        p_t1  = price_values[i + 1]
        gross_return = p_t1 / p_t
        
        # Check if after subtracting fees the trade is profitable
        # We'll require (gross_return - 1) > round_trip_fee_pct
        if (gross_return - 1) > round_trip_fee_pct:
            net_return = gross_return * (1 - round_trip_fee_pct)
            
            # Record the trade details
            trade_info = {
                "BuyDate": price_index[i],
                "BuyPrice": p_t,
                "SellDate": price_index[i + 1],
                "SellPrice": p_t1,
                "GrossReturn": gross_return,
                "NetReturn": net_return,
                "CapitalBefore": capital,  # capital before trade
            }

            # Update capital
            capital = capital * net_return
            trade_info["CapitalAfter"] = capital
            
            trades_list.append(trade_info)

    # Convert the trades list to a DataFrame for easier inspection
    trades_df = pd.DataFrame(trades_list)
    return capital, trades_df

Trying It Out

In your QuantConnect Research Notebook:

  1. Load BTCUSD data (daily resolution) from your chosen date range.
  2. Call the perfect_foresight_daily_with_orders function with your price series and a chosen fee (e.g., 1% = 0.01).
  3. Inspect the final capital multiple and the DataFrame of trades to see which days triggered a buy/sell.

Example usage with a comparison of the algorithm for BTC on Coinbase and SPY on Interactive Brokers.

# 1) BTC on Coinbase: ~1.0% round-trip if we assume 0.5% each side
coinbase_round_trip_fee = 0.01 # 1.0%
btc_final_cap, btc_trades_df = perfect_foresight_daily_with_orders(btc_close, 0.01)

# 2) SPY on Interactive Brokers: ~0.02% round-trip if we assume 0.01% each side
ib_round_trip_fee = 0.0002 # 0.02%
spy_final_cap, spy_trades_df = perfect_foresight_daily_with_orders(spy_close, ib_round_trip_fee)

print(f"Perfect foresight strategy final return (BTC): {btc_final_cap:.2f}x")
print(f"Perfect foresight strategy final return (SPY): {spy_final_cap:.2f}x")
print()
print("BTCUSD Trades executed:\n", btc_trades_df)

The output is

Perfect foresight strategy final return (BTC): 67.58x
Perfect foresight strategy final return (SPY): 9.74x

BTCUSD Trades executed:
        BuyDate  BuyPrice   SellDate  SellPrice  GrossReturn  NetReturn  \
0   2022-01-11  41824.07 2022-01-12   42753.44     1.022221   1.011999   
1   2022-01-12  42753.44 2022-01-13   43920.37     1.027294   1.017021   
2   2022-01-14  42581.65 2022-01-15   43090.72     1.011955   1.001836   
3   2022-01-23  35066.43 2022-01-24   36282.47     1.034678   1.024331   
4   2022-01-24  36282.47 2022-01-25   36693.32     1.011324   1.001210   
..         ...       ...        ...        ...          ...        ...   
208 2023-12-13  41477.39 2023-12-14   42885.54     1.033950   1.023610   
209 2023-12-18  41349.59 2023-12-19   42650.01     1.031449   1.021135   
210 2023-12-20  42266.22 2023-12-21   43674.77     1.033326   1.022992   
211 2023-12-25  43025.03 2023-12-26   43589.67     1.013124   1.002992   
212 2023-12-27  42515.53 2023-12-28   43474.40     1.022553   1.012328   

     CapitalBefore  CapitalAfter  
0         1.000000      1.011999  
1         1.011999      1.029224  
2         1.029224      1.031114  
3         1.031114      1.056202  
4         1.056202      1.057481  
..             ...           ...  
208      62.249193     63.718916  
...
211      66.561625     66.760797  
212      66.760797     67.583815  

[213 rows x 8 columns]

Interpreting the Results

  • The output shows a return on BTC of 67.58% and on SPY of 9.74% after fees for the trading period from Jan 1, 2022, to Jan 1, 2024.
  • The btc_trades_df DataFrame highlights each day where tomorrow’s close was high enough to justify a trade. You’ll see “BuyDate,” “SellDate,” the “GrossReturn” (price ratio), the final “NetReturn” after fees, and how your capital changed.

Realism Check

  1. No one has perfect foresight. This is purely hypothetical.
  2. Fees & Slippage: In actual trading, you might face higher transaction costs, partial fills, or slippage—especially in volatile crypto markets.
  3. Practical Strategies typically use signals (technical indicators, machine learning forecasts, etc.). Imperfect predictions lower returns drastically but allow traders to trade in real-time.

The Bigger Picture: AI and BTC

Bitcoin’s volatility often provides abundant intraday or day-to-day fluctuations, making it enticing for short-term or swing trading. Day-ahead predictions tend to be more reliable than week-ahead forecasts, enhancing the appeal of short-term strategies.

By examining a perfect foresight scenario, we establish an upper limit on how effectively an algorithm could take advantage of daily price moves. In real-world trading, you might aim to approximate that ideal performance using sophisticated indicators, machine-learning techniques, or event-based signals.

Full Source Code

Author

keyboard_arrow_up