I am running an algorithm through Alpaca (Free Paper Trading Account) using Jupyter Notebook, and it is making the proper requests to Alpaca, however, when I run the same algorithm from JupyterLab, I keep getting 403 client errors.
@Aaron_Goffstein A 403 or âForbiddenâ error is caused by one of three things
- the API key/secret key are incorrect or old (ie previous keys after regenerating new ones)
- for Trading API calls the API key+secret key doesnât match the base url (eg one is using their paper API keys but accessing the live base url api.alpaca.markets)
- for Market Data API calls one only has a Free subscription but is trying to access features only available in an âUnlimitedâ subscription.
What specific call are you trying to make which doesnât work in JupyterLab? Is it for Trading API calls or Market Data calls or both? If itâs just the Market Data API calls which donât work then it is simply you are trying to access real-time SIP data with a Free account.
How are you entering your API key and secret key? Is it hardcoded or are you storing them in a file. If the later, ensure that JupyterLab is accessing the correct directory and file. Try hardcoding the keys and see if that works.
I am doing both Market Data calls and Trading API calls, but the error I am getting indicates the problem lies with the market data calls. And as for the keys, they are hardcoded. The issue I am confused about is even with a free account, I was not having any problems with either market data calls or trading api calls when I was running my model from a normal Jupyter Notebook, but when I attempted to run my model from a cloud based service as well as JupyterLab, I was getting these errors.
@Aaron_Goffstein Itâs good that you narrowed the problem to the Market Data APIs. If you are able to execute Trading API calls but not Market Data API calls, the issue is more than likely date related. However, it may have something to do with the versions of python and or underlying packages. Try troubleshooting with some very basic calls.
You didnât mention which SDK you are using (if any) but, using alpaca-trade-api
, try the following in both environments (add your own keys).
!pip install -q alpaca-trade-api
import alpaca_trade_api as alpacaapi
ALPACA_API_BASE_URL = 'https://paper-api.alpaca.markets'
ALPACA_API_KEY = 'xxxxx'
ALPACA_API_SECRET_KEY = 'xxxxx'
api = alpacaapi.REST(ALPACA_API_KEY, ALPACA_API_SECRET_KEY, ALPACA_API_BASE_URL)
bars = api.get_bars('SPY',
'1Day',
start='2020-01-01',
end='2020-02-01',
adjustment='raw',
feed='SIP',
limit=None,
)
display(bars)
If that doesnât work, the issue may be something to do with installed packages. If it does work, then the issue is probably that you are trying to access real-time data with only a Free Market Data subscription.
Perhaps post your code so others can try to reproduce your error?
The test you gave me worked in both environments. And I checked the versions of the installed packages to make sure they were the same in both environments as well. Here is the code where I I am hitting a snag on.
def get_live_data(stock1, stock2, days_back=100):
print(f"Fetching data for {stock1} and {stock2}")
end_time = datetime.now()
start_time = end_time - timedelta(days=days_back)
start_str = start_time.strftime('%Y-%m-%dT%H:%M:%SZ')
end_str = end_time.strftime('%Y-%m-%dT%H:%M:%SZ')
try:
data_stock1 = api.get_bars(stock1, TimeFrame.Day, start_str, end_str, limit=days_back, adjustment='raw').df
data_stock2 = api.get_bars(stock2, TimeFrame.Day, start_str, end_str, limit=days_back, adjustment='raw').df
except Exception as e:
logging.error(f"Failed to fetch data for {stock1} and {stock2}. Reason: {e}")
return None
return pd.DataFrame({
stock1: data_stock1['close'],
stock2: data_stock2['close']
})
# Sample function call
data = get_live_data('ADI', 'MCHP')
Used ADI and MCHP as example pairs (itâs a pairs-trading algo). And this is the error I got from the logging.
@Aaron_Goffstein The issue is the dates/times. The Free Market Data subscription does not provide access to real-time full market SIP data due to licensing restrictions. The most recent 15 minutes of data cannot be fetched. Only SIP data older than 15 minutes can be accessed. I see from the error, the end datetime you specified was 2023-11-01 00:46:58 UTC. That was also the time the request was made. The endpoint is very literal. The specified end time must not be within 15 minutes of the current time. Since it equalled the current time, the request was rejected.
I personally like using the pandas datetime functions. So, to specify the current time minus 15 minutes one could do this. Notice that it is always a good practice to explicitly set the timezone, and for securities, always set it to âmarket timeâ to avoid confusion.
import pandas as pd
# the current market time
current_time = pd.Timestamp('now', tz='America/New_York')
current_time_minus_15_min = current_time - pd.Timedelta('15min')
You mentioned the JupyterLab notebook was in the cloud? The cloud machine probably had a different timezone/clock than your local machine. That change in time, and not the notebook, was what caused the error.
Thank you so much, I got it to work by adapting my datetime function like you said.