Alpaca RSI Trading Bot Based On 1H Yahoo Finance Data

This is the second post in a series to show working examples of trading bots using Alpaca.

A link to the notebook can be found on GitHub.

First I am going to provide a high level overview of the bot and then show a few key parts of the code. The bot does the following:

  • For an array of assets (2 stocks in my example)
  • Pull the 1H yahoo finance data
  • Process it through an RSI trading strategy and determine if buying/selling/do nothing

RSI & Signal Calculations

def calculate_rsi(data, periods, close_column):
    df = pd.DataFrame(data)
    try:
        price_diff = df[close_column].diff(1)
        gain = price_diff.where(price_diff > 0, 0)
        loss = -price_diff.where(price_diff < 0, 0)

        avg_gain = gain.rolling(window=periods).mean()
        avg_loss = loss.rolling(window=periods).mean()

        rs = avg_gain / avg_loss
        rsi = 100 - (100 / (1 + rs))
        df['RSI'] = rsi
    except KeyError as e:
        print(f"Error: {e}")
        print(f"Close column '{close_column}' not found in data.")
        return None

    return df['RSI']

def calculate_buy_sell_signal_rsi(data, periods, thresholds, close_column='Adj Close'):
    data['RSI'] = calculate_rsi(data, periods, close_column)
    signals = pd.DataFrame(index=data.index)
    signals['Signal'] = 'HOLD'
    signals.loc[data['RSI'] > thresholds['overbought_threshold'], 'Signal'] = 'SELL'
    signals.loc[data['RSI'] < thresholds['oversold_threshold'], 'Signal'] = 'BUY'

    return signals, data['RSI'], periods

Get Data & Orders

def connect_to_yfinance(assets, interval, lookback_days=60):
    historical_data = {}
    end_date = datetime.now()
    start_date = end_date - timedelta(days=lookback_days)
    
    for symbol in assets:
        data = yf.download(symbol, interval=interval, start=start_date, end=end_date)
        historical_data[symbol] = data

    return historical_data

def fetch_current_position(symbol):
    try:
        response = requests.get(f'{base_url}/v2/positions/{symbol}', headers={'APCA-API-KEY-ID': api_key, 'APCA-API-SECRET-KEY': api_secret})
        if response.status_code == 200:
            data = response.json()
            return float(data['qty'])
        else:
            return 0.0
    except Exception as e:
        print(f"Error fetching position: {e}")
        return 0.0

def buy_assets(symbol, quantity):
    try:
        order_data = {
            "symbol": symbol,
            "qty": quantity,
            "side": "buy",
            "type": "market",
            "time_in_force": "gtc"
        }
        response = requests.post(f'{base_url}/v2/orders', json=order_data, headers={'APCA-API-KEY-ID': api_key, 'APCA-API-SECRET-KEY': api_secret})
        if response.status_code == 201:
            print(f"Bought {quantity} {symbol} shares")
        else:
            print(f"Error buying {quantity} {symbol} shares: {response.text}")
    except Exception as e:
        print(f"Error buying {quantity} {symbol} shares: {e}")

def sell_assets(symbol, quantity):
    try:
        order_data = {
            "symbol": symbol,
            "qty": quantity,
            "side": "sell",
            "type": "market",
            "time_in_force": "gtc"
        }
        response = requests.post(f'{base_url}/v2/orders', json=order_data, headers={'APCA-API-KEY-ID': api_key, 'APCA-API-SECRET-KEY': api_secret})
        if response.status_code == 201:
            print(f"Sold {quantity} {symbol} shares")
        else:
            print(f"Error selling {quantity} {symbol} shares: {response.text}")
    except Exception as e:
        print(f"Error selling {quantity} {symbol} shares: {e}")

Running It

def main():
    assets_to_trade = ['AAPL', 'GOOGL']
    interval = '1h'
    lookback_days = 60
    rsi_periods = 14
    overbought_threshold = 70
    oversold_threshold = 30
    quantity_to_buy = 5

    thresholds = {
        'overbought_threshold': overbought_threshold,
        'oversold_threshold': oversold_threshold
    }

    historical_data = connect_to_yfinance(assets_to_trade, interval, lookback_days)

    for symbol in assets_to_trade:
        data = historical_data[symbol]
        signals, rsi_values, periods = calculate_buy_sell_signal_rsi(data, rsi_periods, thresholds)

        current_position = fetch_current_position(symbol)
        last_signal = signals['Signal'].iloc[-1]

        print(f"Symbol: {symbol}, Current Position: {current_position}, Last Signal: {last_signal}")

        if last_signal == 'BUY' and current_position == 0:
            buy_assets(symbol, quantity_to_buy)
        elif last_signal == 'SELL' and current_position > 0:
            sell_assets(symbol, current_position)

if __name__ == "__main__":
    main()

Output In Terminal

Sharing

Related Articles

  • All Post
  • Articles
  • Blog Post
  • General Business Automation
  • Portfolio
  • Stock Market & Finance