Skip to content

How to build an automatic trading bot with Simplescraper and GPT-4 Vision

OpenAI, Airtable and Simplescraper image cover


Now that Large Language Models can ‘see’, it’s helpful to think about how we can use them as tools to act on our behalf. In this guide we’ll explore a popular activity—trading stocks—and harness the magic of OpenAI’s GPT-Vision to analyze charts and make trading decisions based on price structure.

How will it work? Simplescraper will visit TradingView and take a screenshot of the chart of an asset of our choice. We’ll then send that screenshot to OpenAI’s GPT-4 Vision along with a prompt instructing the AI exactly what to decipher from the chart. Based on that information we’ll decide to make a trade or not. If we decide to go ahead, we’ll make an API call to a trading platform (like MEXC) to buy the asset.

Once it’s up and running, we can schedule this process to run as frequently as we like. All fully automated, including the important decision-making part.

There’s a small amount of code involved but it’s super simple and already written for you. So coders and no-coders alike, please read on. Let’s get started.

Take a screenshot of Tradingview

First, we’ll need an up-to-date chart. This step is easy using Simplescraper. Click here to find a recipe that will scrape Tradingview BTC/USD chart and return the body text, as well as a screenshot. Save the recipe to your Simplescraper dashboard.

After saving the recipe, run the scrape recipe and after a few seconds you should see results. Since we’re interested in accessing the result programmatically, click on the ‘API’ tab and note the API URL. Visit this URL in your browser (or click the ‘preview’ button) and you’ll notice a JSON structure containing the scraped data, including the screenshot URL. We'll use this in a later step.

screenshot of API tab in Simplescraper

Now that we have the screenshot, it’s time to get AI’s opinion on what’s happening on the chart and whether trading opportunities exist.

Construct a prompt

We’ll first need a prompt that instructs the AI to read the chart exactly how we want it to. Prompting an AI involves a degree of trial and error, and after dozens of tests we’ve found this to be a good prompt which considers the basics of technical analysis and nudges the AI to make a decision:

Analyze the daily stock price chart and generate a JSON decision, prioritizing the identification of support levels and upward trends:

Trend Analysis: Compare current price with the past 1, 3, 7, 14, 21, and 30 days to identify the trend direction, emphasizing recent upward trends and interactions with support zones.

Momentum: Assess the speed and direction of price movements, noting bar size and color, and wick behavior, particularly when price is near or bouncing off support.

Support and Resistance: Determine local and macro support and resistance levels from daily bars, focusing on the proximity of current price to support zones rather than exact prices.

Commentary and Strategy: Provide concise commentary based on the analysis, emphasizing the presence of support zones, reversals and upward trends. Suggest a trading strategy that prioritizes buying close to confirmed support, reclaiming of support or on breakouts above resistance.

Decision Weighting: Rate the buying opportunity from 1 (no buy) to 10 (strong buy), giving higher scores when the price is near or bouncing off support zones in an upward trend. Align the score with the trend, price action, patterns, and strategy.

Consider the full price history overall context. If the chart is unclear, set values to null and explain. Conclude with the decision weight and a concise explanation, emphasizing the reasoning behind the score based on support and upward trend identification. If you don't see a clear buying opportunity, explain what would have to change to modify your score, and include a target price range. Don't assume trend will continue - imagine trend was to reverse and suggest what price it would need to reach to change outlook.
Example output:

{
"Trend": "upward",
"Current_price": 5000,
"Support_short_term": ["1180-1200"],
"Support_long_term": ["1080-1120"],
"Resistance_short_term": ["5500"],
"Resistance_long_term": ["7000"],
"Decision_weight": 8,
"Commentary": "Upward trend confirmed, with price bouncing off the support zone at 1180-1200. This reaction strengthens the bullish sentiment.The presence of a potential Ascending Triangle pattern and the price's proximity to support suggest a strong buy signal."
}

In this prompt, we ask the AI to use Technical Analysis, specifically support and resistance zones, and price momentum to determine if the chart setup supports a buy or sell decision.

We also ask the AI to assign a decision weight from 0 to 10 based on how confident it is that the conditions for taking a trading position exist. This is an easy way to measure if the correct trading conditions have been met and allows us to initiate a trade only when a threshold has been reached, for example, a score of 7 or higher.

Of course, you can tweak this prompt or replace it entirely depending on which elements of the price action you wish the AI to focus on.

Analyze the chart using GPT-4 Turbo with Vision and (optionally) make a trade

At this stage we have our screenshot and our prompt so we’re ready to outsource our trading decision-making to AI. Let’s piece everything together using code. Here’s the entire Javascript code with comments explaining exactly what’s happening:

javascript
// An auto-trading bot built on Simplescraper and GPT4-vision

// REPLACE WITH YOUR OWN VALUES
const config = {
    simpleScraperApiUrl: 'https://simplescraper.io/api/somerecipeid?apikey=yourSimplescraperApiKey',
    openaiApiKey: 'yourOpenAiApiKey',
    mexcAccessKey: 'yourMexcAccessKey',
    mexcSecretKey: 'yourMexcSecret',
    symbol: 'BTCUSDC',
    decision_threshold: 7,
    usd_to_spend: 10,
    place_trade: true
};

// DO NOT NEED TO CHANGE CODE BELOW HERE

const crypto = require('crypto');

const prompt = `Analyze the daily stock price chart and generate a JSON decision, prioritizing the identification of support levels and upward trends:

Trend Analysis: Compare current price with the past 1, 3, 7, 14, 21, and 30 days to identify the trend direction, emphasizing recent upward trends and interactions with support zones.
Momentum: Assess the speed and direction of price movements, noting bar size and color, and wick behavior, particularly when price is near or bouncing off support.
Support and Resistance: Determine local and macro support and resistance levels from daily bars, focusing on the proximity of current price to support zones rather than exact prices.
Commentary and Strategy: Provide concise commentary based on the analysis, emphasizing the presence of support zones, reversals and upward trends. Suggest a trading strategy that prioritizes buying close to confirmed support, reclaiming of support or on breakouts above resistance.
Decision Weighting: Rate the buying opportunity from 1 (no buy) to 10 (strong buy), giving higher scores when the price is near or bouncing off support zones in an upward trend. Align the score with the trend, price action, patterns, and strategy.

Consider the full price history overall context. If the chart is unclear, set values to null and explain. Conclude with the decision weight and a concise explanation, emphasizing the reasoning behind the score based on support and upward trend identification. If you don't see a clear buying opportunity, explain what would have to change to modify your score, and include a target price range. Don't assume trend will continue - imagine trend was to reverse and suggest what price it would need to reach to change outlook.
Example output:
{
"Trend": "upward",
"Current_price": 5000,
"Support_short_term": ["1180-1200"],
"Support_long_term": ["1080-1120"],
"Resistance_short_term": ["5500"],
"Resistance_long_term": ["7000"],
"Decision_weight": 8,
"Commentary": "Upward trend confirmed, with price bouncing off the support zone at 1180-1200. This reaction strengthens the bullish sentiment.The presence of a potential Ascending Triangle pattern and the price's proximity to support suggest a strong buy signal."
}`;


// Fetches image URLs using the Simplescraper API
async function fetchImageUrlUsingSimplescraper(apiUrl, runNow) {
    try {

        const url = runNow ? `${config.simpleScraperApiUrl}&run_now=true` : config.simpleScraperApiUrl;
        const response = await fetch(url);
        const data = await response.json();
        return data.screenshots || null;

    } catch (error) {
        console.error('Failed to fetch image URL:', error);
        return null;
    }
}


// Uses OpenAI API to extract details from an image given its URL
async function analyzeImageUsingAi(imageUrl, prompt) {
    const apiKey = config.openaiApiKey;  // Securely managed API key
    const apiEndpoint = 'https://api.openai.com/v1/chat/completions';

    const headers = {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiKey}`
    };

    const requestBody = {
        model: "gpt-4-turbo",
        temperature: 0.1,
        response_format: { "type": "json_object" },
        messages: [
            {
                role: "user",
                content: [
                    { type: "text", text: prompt },
                    { type: "image_url", image_url: { "url": imageUrl} }
                ]
            }
        ]
    };

    try {
        const response = await fetch(apiEndpoint, {
            method: 'POST',
            headers: headers,
            body: JSON.stringify(requestBody)
        });

        const data = await response.json();
        // console.log('OpenAI response:', data.choices);
        return data.choices?.[0]?.message?.content || null;

    } catch (error) {
        console.error('Failed to extract image details:', error);
        return null;
    }
}


// process the decision and possibly send a trade order
async function processDecision(jsonData) {
    try {
        const decisionWeight = Number(jsonData.Decision_weight);
        if (isNaN(decisionWeight)) {
            console.error('Decision_weight is not a number');
            return { success: false, error: 'Decision_weight is not a number' };
        }

        if (decisionWeight >= config.decision_threshold) {
            console.log('Decision_weight threshold met, sending trade order...');
            const orderResponse = await sendMarketTradeOrder(config.symbol, config.usd_to_spend);
            return { success: true, data: orderResponse };
        } else {
            console.log('Decision_weight does not meet the threshold.');
            return { success: false, error: 'Threshold not met' };
        }
    } catch (error) {
        console.error('Error processing decision:', error);
        return { success: false, error: error.message };
    }
}


// send a market trade order to MEXC to buy BTC with a specified amount of USDC
async function sendMarketTradeOrder(symbol, quoteOrderQty) {
    console.log('Sending market trade order...');
    const endpoint = 'https://api.mexc.com/api/v3/order';
    const timestamp = new Date().getTime();
    const recvWindow = 15000;

    const params = {
        symbol,
        side: 'BUY',
        type: 'MARKET',
        quoteOrderQty,
        timestamp,
        recvWindow
    };

    const signature = createSignature(params);
    params.signature = signature;

    try {
        const response = await fetch(`${endpoint}?${new URLSearchParams(params)}`, {
            method: 'POST',
            headers: {
                'X-MEXC-APIKEY': config.mexcAccessKey,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(params)
        });

        const data = await response.json();
        if (!data || data.code) {
            throw new Error(`API error: ${data.msg}`);
        }
        return data;
    } catch (error) {
        console.error('Failed to send market trade order:', error);
        throw error;
    }
}


// create a HMAC SHA256 signature - called by sendMarketTradeOrder
function createSignature(params) {
    const queryString = Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&');
    return crypto.createHmac('sha256', config.mexcSecretKey).update(queryString).digest('hex');
}


// Main function - call functions from here to fetch image, analyze and make a trade -----------------------------------
async function main(prompt, runNow = true) {
    console.log("1. Getting screenshot...");
    const apiUrl = config.simpleScraperApiUrl;
    const imageArr = await fetchImageUrlUsingSimplescraper(apiUrl, runNow);

    if (!imageArr?.length) {
        console.log('No screenshot returned');
        return;
    }
    
    console.log('Screenshot URL:', imageArr[0]);
    console.log("2. Analyzing screenshot with AI...");
    const analysis = await analyzeImageUsingAi(imageArr[0], prompt);

    if (!analysis) {
        console.log('Failed to extract details from the screenshot');
        return;
    }

    const jsonData = JSON.parse(analysis);
    console.log('AI analysis:', jsonData);
    
    if (config.place_trade) {
        console.log("3. Processing trading decision...");
        const decisionResult = await processDecision(jsonData);

        if (!decisionResult.success) {
            console.error('Decision process failed:', decisionResult.error);
            return;
        }

        console.log('Decision processed successfully:', decisionResult.data);
    }
    
}

main(prompt, false); // Run the main function

And here’s what each function is doing:

fetchImageUrlUsingSimplescraper: Fetches the image of the price chart via the Simplescraper API.

extractImageDetailsUsingAi: Uses the OpenAI API to extract details from the image.

processDecision: Determines if the threshold for a trade has been met and, if so, places the trade.

sendMarketTradeOrder: Handles the actual trading.

main: Manages all of the above functions.

Configure your API keys and preferences

The only modifications you need to make are to the config object at the beginning of the code.

OpenAI, Airtable and Simplescraper image cover

Update the following keys with your own information:

  • simpleScraperApiUrl: This can be found on the API tab of your recipe on the Simplescraper dashboard (be sure to toggle run_now to true)

  • openaiApiKey: Your OpenAI API key can be found here

  • mexcAccessKey: Your MEXC key can be found here

  • mexcSecretKey: Your MEXC secret can be found here (same process as the previous step)

  • symbol: The symbol being traded. For simplicity the default is the BTC-USCD pair on MEXC

  • decision_threshold: How confident the AI has to be in the buying opportunity to make a trade (1 -10)

  • usd_to_spend: The amount you want to spend for each trade

  • place_trade: Set to true if you want to take the trade, or false if you only require the analysis

Some things to note:

  • MEXC only allows USDC via the API, and not USDT, so ensure you have USDC in your spot account
  • When creating your MEXC access key, enable the BTC/USDC trading pair

Run the code

Once you've added your information, you're ready to run the code. You can copy the code and test this locally if you have Node installed (version 18 or above is recommended). Or you can click here to edit the code on val.town, a website that allows you to easily deploy Javascript, and run it immediately.

After adding your own configuration details, all you have to do is run the code and your auto-trading bot will do its thing - generate the screenshot via Simplescraper, analyze the chart via GPT-4 Vision, come to a decision, and make a trade on MEXC . All in about 12 seconds.

Here's how this looks running on val.town in real time:

Scrape and see everything

Congratulations, you've just created an automated decision-making and trading system using Simplescraper, the latest AI and about 200 lines of code. While automated trading is an interesting place to start, it only scratches the surface of what's possible with combining web scraping, and multi-modal AI systems. With these basic building blocks, you can build workflows in other domains - open-source intelligence, website monitoring, automated agents and more.

Anything you can see on the web, now an AI can see too - meaning endless opportunities to build cool things.

Links mentioned in this article:

Build with Simplescraper

Turn websites into structured data in seconds.