# Real time callback different than historical quotes?

**URL:** <https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171>\
**Category:** Alpaca Market Data\
**Created:** [November 29, 2022, 5:54am UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171 "2022-11-29T05:54:06Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![rock](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/rock/32/4872_2.png) [@rock](https://forum.alpaca.markets/u/rock)\
**Post date:** [November 29, 2022, 5:54am UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/1 "2022-11-29T05:54:06Z")

</div>

I was playing around with the APIs and found the real time quote callback through **StockDataStream:subscribe\_quotes** can give very different price data for some symbols than what’s pulled from **StockHistoricalDataClient:get\_stock\_quotes**. The StockDataStream contains level 2 book data while the StockHistoricalDataClient is comparatively much closer to the _real_ price. As an example, below is **WYNN** streaming vs. historical quotes for the same time period that you can see the difference from the highlights. Am I missing any filter or supposed to use specific exchange? Anyone has idea of how to get rid of the level 2 “noises”? Thanks!

 ![SCR-20221128-u5t](https://us1.discourse-cdn.com/flex020/uploads/alp/original/2X/3/3ca76f97627d387df6568d25890bc41ecc73c0a5.png)

---

<div class="post-metadata">

**Author:** ![rock](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/rock/32/4872_2.png) [@rock](https://forum.alpaca.markets/u/rock)\
**Post date:** [November 30, 2022, 6:48am UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/2 "2022-11-30T06:48:40Z")

</div>

anyone to address this? 🥵

---

<div class="post-metadata">

**Author:** ![Gergely\_Alpaca](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/gergely_alpaca/32/3210_2.png) [@Gergely\_Alpaca](https://forum.alpaca.markets/u/Gergely_Alpaca)\
**Post date:** [December 12, 2022, 9:15am UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/3 "2022-12-12T09:15:24Z")

</div>

> [@Large Spread Gap in Real Time Data](https://forum.alpaca.markets/t/large-spread-gap-in-real-time-data/11206/4):
>
> Hey wave You’re comparing the free IEX stream with the SIP data in historical. Both StockDataStream and StockHistoricalDataClient has a feed argument. If you want quotes from all US exchanges, use the SIP value for the feed (this requires Unlimited Subscription for the stream and for the last 15 minutes in historical). If you want to get IEX quotes, use the IEX value. This means that only quotes from the IEX (v) exchange are included: you can see this in the ask\_exchange and bid\_exchange fiel…

---

<div class="post-metadata">

**Author:** ![JeremyWhittaker](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/jeremywhittaker/32/3239_2.png) [@JeremyWhittaker](https://forum.alpaca.markets/u/JeremyWhittaker)\
**Post date:** [May 1, 2023, 6:38pm UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/4 "2023-05-01T18:38:44Z")

</div>

I’m trying to move my algos over to Alpaca and one went rogue during testing. I noticed the same thing as you. I’m wondering if this would be fixed by subscribe\_trades rather than subscribe\_quotes. But regardless, does this mean Alpaca is quoting 27.5 point spread on BRK.B? That should be a highly liquid stock with very minimal spread.

 ![image](https://us1.discourse-cdn.com/flex020/uploads/alp/original/2X/9/9d60a1bd7356296ed308932a5004dfb0e7723c1a.png)

---

<div class="post-metadata">

**Author:** ![JeremyWhittaker](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/jeremywhittaker/32/3239_2.png) [@JeremyWhittaker](https://forum.alpaca.markets/u/JeremyWhittaker)\
**Post date:** [May 1, 2023, 7:02pm UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/5 "2023-05-01T19:02:44Z")

</div>

This can’t be accurate during market hours…

 ![image](https://us1.discourse-cdn.com/flex020/uploads/alp/original/2X/6/6e35689709f50f22061960f6e7aeb0974caf6cdf.jpeg)

> [@JeremyWhittaker](#):
>
> I’m trying to move my algos over to Alpaca and one went rogue during testing. I noticed the same thing as you. I’m wondering if this would be fixed by subscribe\_trades rather than subscribe\_quotes. But regardless, does this mean Alpaca is quoting 27.5 point spread on BRK.B? That should be a highly liquid stock with very minimal spread.

---

<div class="post-metadata">

**Author:** ![Gergely\_Alpaca](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/gergely_alpaca/32/3210_2.png) [@Gergely\_Alpaca](https://forum.alpaca.markets/u/Gergely_Alpaca)\
**Post date:** [May 2, 2023, 7:09am UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/6 "2023-05-02T07:09:53Z")

</div>

@JeremyWhittaker The answer is the same: if you’re using the free plan, you can only see the IEX book.

---

<div class="post-metadata">

**Author:** ![JeremyWhittaker](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/jeremywhittaker/32/3239_2.png) [@JeremyWhittaker](https://forum.alpaca.markets/u/JeremyWhittaker)\
**Post date:** [May 2, 2023, 2:27pm UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/7 "2023-05-02T14:27:45Z")

</div>

I guess I don’t know market depth enough to understand what is going on here. Are people really paying those prices on IEX? Or is the data trash?

---

<div class="post-metadata">

**Author:** ![Gergely\_Alpaca](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/gergely_alpaca/32/3210_2.png) [@Gergely\_Alpaca](https://forum.alpaca.markets/u/Gergely_Alpaca)\
**Post date:** [May 2, 2023, 2:46pm UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/8 "2023-05-02T14:46:45Z")

</div>

@JeremyWhittaker The data is not trash, it shows the top of the book on the IEX exchange, which is only one of the many exchanges. If you see for example bid $305 - ask $330 on that single exchange that means there is someone, who is willing to buy that security for $305, and another someone, who’s willing to sell it for $330. All trades must happen within this range. But, crucially, other exchanges might have much better rates, e.g. someone on another exchange might be selling for $320.

Our unlimited plan provides you access to the best bid and ask across all exchanges. In the above example that could be for example $315 x $316.

---

<div class="post-metadata">

**Author:** ![JeremyWhittaker](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/jeremywhittaker/32/3239_2.png) [@JeremyWhittaker](https://forum.alpaca.markets/u/JeremyWhittaker)\
**Post date:** [May 2, 2023, 2:58pm UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/9 "2023-05-02T14:58:29Z")

</div>

I have the unlimited plan. I just didn’t want to trade this particular algo in my live account. This code was for testing. I’m going to modify my code to pull quotes from my live key instead of demo.

Regarding these prices. I find it hard to believe people are paying these drastically different prices. Something doesn’t seem right to me.

---

<div class="post-metadata">

**Author:** ![JeremyWhittaker](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/jeremywhittaker/32/3239_2.png) [@JeremyWhittaker](https://forum.alpaca.markets/u/JeremyWhittaker)\
**Post date:** [May 2, 2023, 5:22pm UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/10 "2023-05-02T17:22:36Z")

</div>

> [@Gergely\_Alpaca](#):
>
> @JeremyWhittaker The data is not trash, it shows the top of the book on the IEX exchange, which is only one of the many exchanges. If you see for example bid $305 - ask $330 on that single exchange that means there is someone, who is willing to buy that security for $305, and another someone, who’s willing to sell it for $330. All trades must happen within this range. But, crucially, other exchanges might have much better rates, e.g. someone on another exchange might be selling for $320.

These are the spreads on BRK.B today. I find it hard to believe Berkshire baby B’s have a spread of 141 points on a stock that is worth $324. That’s a 43.5% spread.

 ![image](https://us1.discourse-cdn.com/flex020/uploads/alp/original/2X/9/9651b76300360c32ca6678b80da5e29d414569fd.jpeg)

Or look at any of these stocks. these spreads are absurd.

 ![image](https://us1.discourse-cdn.com/flex020/uploads/alp/original/2X/e/eac4e73eff1065d08bd1562e3009cd8f17948dea.jpeg)

 ![image](https://us1.discourse-cdn.com/flex020/uploads/alp/original/2X/4/45a5812dab6a441f09d916f7341c7e0c0922c231.jpeg)

 ![image](https://us1.discourse-cdn.com/flex020/uploads/alp/original/2X/f/f6a3c060b0eb1844a469e0c5542a7fd8abacc5b8.jpeg)

 ![image](https://us1.discourse-cdn.com/flex020/uploads/alp/original/2X/c/c791eb4c8719c2427bba51bb9508474d23ccc037.jpeg)

 ![image](https://us1.discourse-cdn.com/flex020/uploads/alp/original/2X/1/1a69a55aa8b08bf09f362c2718746ea582e1dde6.jpeg)

 ![image](https://us1.discourse-cdn.com/flex020/uploads/alp/original/2X/0/0a58ff317e34878132e9aec503f8a619322e8267.jpeg)

---

<div class="post-metadata">

**Author:** ![Gergely\_Alpaca](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/gergely_alpaca/32/3210_2.png) [@Gergely\_Alpaca](https://forum.alpaca.markets/u/Gergely_Alpaca)\
**Post date:** [May 3, 2023, 8:00am UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/11 "2023-05-03T08:00:30Z")

</div>

Please share the code how you’re calculating these.

---

<div class="post-metadata">

**Author:** ![JeremyWhittaker](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.alpaca.markets/jeremywhittaker/32/3239_2.png) [@JeremyWhittaker](https://forum.alpaca.markets/u/JeremyWhittaker)\
**Post date:** [May 4, 2023, 7:48pm UTC](https://forum.alpaca.markets/t/real-time-callback-different-than-historical-quotes/11171/12 "2023-05-04T19:48:15Z")

</div>

I believe specifying SIP(as you previously suggested) fixed the code:  
wss\_client = CustomStockDataStream(LIVE\_API\_KEY, LIVE\_SECRET\_KEY, data\_feed=‘sip’)

But without data\_feed=‘sip’ that is how I generated those charts.

```auto
def store_minute_data(symbol, bid, ask):
    now = datetime.datetime.now()
    timestamp = now.replace(second=0, microsecond=0)

    if symbol not in minute_data:
        minute_data[symbol] = pd.DataFrame(columns=['timestamp', 'bid', 'ask'])

    # Update the data for the current minute
    if not minute_data[symbol].empty and minute_data[symbol].iloc[-1]['timestamp'] == timestamp:
        minute_data[symbol].iloc[-1] = [timestamp, bid, ask]
    else:
        new_data = pd.DataFrame({'timestamp': timestamp, 'bid': bid, 'ask': ask}, index=[0])
        minute_data[symbol] = pd.concat([minute_data[symbol], new_data], ignore_index=True)

    # Save the data to disk
    today_date = datetime.datetime.now().strftime("%Y-%m-%d")
    folder_path = 'data'
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)
    file_path = f'{folder_path}/{symbol}_{today_date}_minute_data.pickle'

    if os.path.exists(file_path):
        with open(file_path, 'rb') as f:
            existing_data = pickle.load(f)
            combined_data = pd.concat([existing_data, minute_data[symbol]]).drop_duplicates(subset='timestamp', keep='last').reset_index(
                drop=True)
    else:
        combined_data = minute_data[symbol]

    with open(file_path, 'wb') as f:
        pickle.dump(combined_data, f)

```

```auto
async def quote_data_handler(data):
    if market_status_open == False:
        print(f'\033[33mMarket is closed, waiting for market to open in {time_to_market_open} seconds\033[0m')
        await asyncio.sleep(time_to_market_open)

    store_minute_data(data.symbol, data.bid_price, data.ask_price)
    prices[data.symbol] = {'bid': data.bid_price, 'ask': data.ask_price}

    current_spread = get_alpaca_spread(data.symbol)
    # if current_spread is not None:
    # print(f'{data.symbol}: Current spread: {current_spread:.2f} & Max Spread:{MAX_SPREAD}')
    # else:
    # print(f'{data.symbol}: Current spread not available')
    if current_spread != None and current_spread > MAX_SPREAD:
        if data.symbol not in spread_too_high:
            spread_too_high.append(data.symbol)
            print(f'\033[33m{data.symbol}: Blacklisting, as the spread {current_spread} is higher than the max {MAX_SPREAD}\033[0m')
            # print(f'\033[33mThese symbols currently have a spread higher than {MAX_SPREAD}%\033[0m')
            # print(spread_too_high)
    elif current_spread != None and current_spread < MAX_SPREAD:
        if data.symbol in spread_too_high:
            spread_too_high.remove(data.symbol)
            print(f'\033[32m{data.symbol}: Removing from blacklist. Spread dropped below threshold\033[0m')
            # print(f'\033[33mThese symbols still have a spread higher than {MAX_SPREAD}%\033[0m')
            # print(spread_too_high)

```

```auto
async def monitor_stocks():
    if market_status_open == False:
        print(f'\033[33mMarket is closed, waiting for market to open in {time_to_market_open} seconds\033[0m')
        await asyncio.sleep(time_to_market_open)

    wss_client = CustomStockDataStream(LIVE_API_KEY, LIVE_SECRET_KEY, data_feed='sip')

    wss_client.subscribe_quotes(quote_data_handler, regressor_symbol)
    # print(f'Subscribing to {symbols}')
    for symbol in symbols_to_trade:
        wss_client.subscribe_quotes(quote_data_handler, symbol)

    while True:
        try:
            await wss_client.run()
        except (AttributeError, ConnectionClosedError) as e:
            if "resume_reading" in str(e) or isinstance(e, ConnectionClosedError):
                print("\033[31mEncountered websocket error, retrying connection in 5 seconds...\033[0m")
                await asyncio.sleep(5)
            else:
                raise
        except asyncio.exceptions.TimeoutError:
            print("\033[31mConnection timed out. Retrying in 10 seconds...\033[0m")
            await asyncio.sleep(10)
        except Exception as e:
            print(f"\033[31mUnexpected error. Retrying in 60 seconds: {e}\033[0m")
            await asyncio.sleep(60)

```
