To build this webpage, I wanted to use only available free tools for AI, charts and retrieve the stock prices.
Reminder: The implementations described here should be used only on a local computer only, since it exposes an API-KEY which should never be available online. For a commercial webpage, it should always use a server side to request the stocks names and prices instead of making api calls on the client side.
This article describes my journey to attempt to achieve this goal using Google Gemini 1.5 and ChatGPT 4o chatbox.
Update: Added the results of the unofficial version of ChatGPT 5.
It’s also possible to call ChatGPT via API, which is preferable to those who have paid plans, but I wanted to make it easier to be reproducible by the reader by simply using the chatbox.
At the end of the article, there is the final conclusion of this experiment and a comparison between the results generated by both AI code assistants chatboxes.
Setup
To retrieve the stock market prices, I use twelvedata.com website, which provides an API on its free plan.
You will need to:
- Register at the twelvedata.com website.
- Setup an api key.
Google Gemini
I started with Google Gemini 1.5 chatbox to see how it was able to understand my request.
The prompt:
create `html` and `javascript` website:
- use bootstrap 5 and jquery.
- it should have the following input files at the left top using css classes: `form-control d-inline ms-2` and `max-width: 200px`.
- The first input field is `ticker` and it represents a stock ticker.
- The second field should be `refresh-rate` and it represents the time to retrieve the stocks. it should be fill with number 5.
- The third field is `min-value` and it represents an alarm if the latest stock price is under this value.
- The fourth field is `max-value` and it represents an alarm if the latest stock price is above this value.
- get the stock names and values from `twelvedata`.
- the api key should be in the `api-key.js` file.
- create a `.gitignore` to exclude `api-key.js`.
- the `ticker` should support suggestions with the names from `twelvedata` api endpoint `/stocks`.
- after the user fills the `ticker` field, and presses `enter` key, check if it matches a stock name, if it does, get the stock values.
- after retrieving the stock prices, plot a candlestick chart.
- each candlestick has at the top `high` value, at the bottom the `low` value.
- plot a linear chart for the `open` values.
- display an `X` axis, the labels for the date, and `Y` axis, the labels for the stock price.
- if the user clicks on the chart, display a vertical bar at that position and display a label with the date and open,high,low of the stock price.
- the stocks retrieval and chart should be updated every `refresh-rate` minute.
- if `min-value` field is a valid number, and the most recent open is below that value, it should do a `window.alert` instructing the user that the value is below `min-value`.
- if `max-value` field is a valid number, and the most recent open is above that value, it should do a `window.alert` instructing the user that the value is above `max-value`.
Google Gemini response
From this chatbox prompt, Google Gemini generated the following files:
The file structure:
stock-analysis/
├── index.html
├── api-key.js
├── script.js
├── style.css
└── .gitignore
The
index.html
file:<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stock Analysis</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T384r9gHJA7C5t2Zrvu1AgMEQf240+iLOaOg938KBLDnZqPBfXVr1tJ+hVOWrBlH+D" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="stylesheet" href=style.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-3">
<input type="text" id="ticker" class="form-control d-inline ms-2" max-width="200px" placeholder="Ticker">
<input type="number" id="refresh-rate" class="form-control d-inline ms-2" max-width="200px" value="5">
<input type="number" id="min-value" class="form-control d-inline ms-2" max-width="200px" placeholder="Min value">
<input type="number" id="max-value" class="form-control d-inline ms-2" max-width="200px" placeholder="Max value">
</div>
<div class="col-md-9">
<canvas id="myChart"></canvas>
</div>
</div>
</div>
<script src="api-key.js"></script>
<script src="script.js"></script>
</body>
</html>
The
style.css
file:/* Add your custom styles here */
The
.gitignore
file:api-key.js
The
api-key.js
file:const apiKey = 'YOUR_TWELVEDATA_API_KEY';
The
script.js
file:$(document).ready(function () {
const apiKey = window.apiKey; // Access API key from api-key.js
const chartCanvas = document.getElementById('myChart');
let chart;
$('#ticker').keypress(function (e) {
if (e.which === 13) { // Enter key pressed
const ticker = $(this).val().toUpperCase();
getStockData(ticker);
}
});
function getStockData(ticker) {
$.ajax({
url: `https://api.twelvedata.com/time_series?symbol=${ticker}&interval=1day&apikey=${apiKey}`,
method: 'GET',
success: function (data) {
// Handle successful response
const stockData = data.values.map(value => ({
time: new Date(value.datetime),
open: parseFloat(value.open),
high: parseFloat(value.high),
low: parseFloat(value.low),
close: parseFloat(value.close)
}));
createChart(stockData);
startRefreshInterval();
},
error: function (error) {
// Handle error
console.error('Error fetching stock data:', error);
}
});
}
function createChart(stockData) {
if (chart) {
chart.destroy();
}
chart = new Chart(chartCanvas, {
type: 'candlestick',
data: {
datasets: [{
label: 'Stock Price',
data: stockData,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1
}]
},
options: {
// Chart configuration options
scales: {
x: {
type: 'time',
time: {
unit: 'day'
}
},
y: {
beginAtZero: true
}
},
plugins: {
tooltip: {
callbacks: {
label: function (context) {
const label = context.dataset.label || '';
const dataPoint = context.parsed;
return `${label}: ${dataPoint.y}`;
}
}
},
annotation: {
annotations: {
verticalLine: {
type: 'line',
scaleID: 'x',
xValue: null,
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 2
}
}
},
}
},
});
chart.options.plugins.annotation.annotations.verticalLine.label = {
enabled: false,
content: 'Loading...',
position: 'top'
};
chart.options.onClick = function (event, active) {
const index = active[0].index;
const dataPoint = chart.data.datasets[0].data[index];
chart.options.plugins.annotation.annotations.verticalLine.xValue = dataPoint.time;
chart.options.plugins.annotation.annotations.verticalLine.label.content = `Date: ${dataPoint.time.toLocaleDateString()}<br>Open: ${dataPoint.open}<br>High: ${dataPoint.high}<br>Low: ${dataPoint.low}`;
chart.options.plugins.annotation.annotations.verticalLine.label.enabled = true;
chart.update();
};
}
function startRefreshInterval() {
const refreshRate = parseInt($('#refresh-rate').val());
setInterval(function () {
getStockData($('#ticker').val());
}, refreshRate * 60 * 1000);
const minValue = parseFloat($('#min-value').val());
const maxValue = parseFloat($('#max-value').val());
if (!isNaN(minValue) && stockData[stockData.length - 1].open < minValue) {
window.alert(`Stock price is below the minimum value of ${minValue}`);
}
if (!isNaN(maxValue) && stockData[stockData.length - 1].open > maxValue) {
window.alert(`Stock price is above the maximum value of ${maxValue}`);
}
}
});
Google Gemini response issues
The first Google Gemini response didn’t provide a complete script.js
code, I had to ask to complete it, in order to get more code, and then merge the code with the previous code.
After having the entire javascript code, I changed the value of api-key.js
to my apiKey
.
Once I view the webpage on a web browser, I found the following issues:
- 👎️ The
href
on theindex.html
file doesn’t start with./
, therefore it only works on a website root. I tweak it manually:
<script src="./api-key.js"></script>
<script src="./script.js"></script>
- 👎️ The
apiKey
onapi-key.js
starts withconst
, with this const, it won’t be accessible toscript.js
. It worked, after changing to:
apiKey = 'YOUR_TWELVEDATA_API_KEY';
- 👎️ The line with
const chartCanvas = document.getElementById('myChart');
misses the.getContext('2d');
at the end.
It should be:
const chartCanvas = document.getElementById('myChart').getContext('2d');
After these changes above, there was still no chart being displayed.
I went to dig up the documentation code of
chartjs
, and I discovered that it didn’t support the candlestick
type.Instead of thinking that the output was a complete hallucinogenic response of Google Gemini, or spending an immense time researching, I gave it a pause, and tried to use ChatGPT chatbox, this later added an extra external script:
chartjs-chart-financial
.- 👎️ The package
chartjs
which doesn’t supportcandlestick
type, but the npm package pluginchartjs-chart-financial
adds this functionality.
Therefore, I added this functionality to the html file:
<script src="https://cdn.jsdelivr.net/npm/chartjs-chart-financial"></script>
I continued my attempts on the ChatGPT and after being able to see a graph plot, even not coherent with what I wanted, it gave me the insight to quickly determine the problem.
From the ChatGPT attempt, I was able to find the correct external scripts, as described in ChatGPT chatbox response issues.
After all these changes, it wasn’t still able to produce a simple chart.
I compared with ChatGPT results, and I discovered these script lines were incorrect:
const stockData = data.values.map(value => ({
time: new Date(value.datetime),
open: parseFloat(value.open),
high: parseFloat(value.high),
low: parseFloat(value.low),
close: parseFloat(value.close)
}));
It should be:
const stockData = data.values.map(value => ({
x: new Date(value.datetime),
o: parseFloat(value.open),
h: parseFloat(value.high),
l: parseFloat(value.low),
c: parseFloat(value.close)
}));
Finally, I was able to see a chart being plotted. It wasn’t what I expected but at this point it was enough to have a better notion of the capabilities of Google Gemini code generation.
Google Gemini manually tweaked response
The end result after the previous tweaks.
index.html
file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stock Analysis</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T384r9gHJA7C5t2Zrvu1AgMEQf240+iLOaOg938KBLDnZqPBfXVr1tJ+hVOWrBlH+D" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luxon@3.4.4"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.3.1"></script>
<script src="https://www.chartjs.org/chartjs-chart-financial/chartjs-chart-financial.js" type="text/javascript"></script>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-3">
<input type="text" id="ticker" class="form-control d-inline ms-2" max-width="200px" placeholder="Ticker">
<input type="number" id="refresh-rate" class="form-control d-inline ms-2" max-width="200px" value="5">
<input type="number" id="min-value" class="form-control d-inline ms-2" max-width="200px" placeholder="Min value">
<input type="number" id="max-value" class="form-control d-inline ms-2" max-width="200px" placeholder="Max value">
</div>
<div class="col-md-9">
<canvas id="myChart"></canvas>
</div>
</div>
</div>
<script src="./api-key.js"></script>
<script src="./script.js"></script>
</body>
</html>
The
script.js
file:$(document).ready(function () {
const apiKey = window.apiKey; // Access API key from api-key.js
const chartCanvas = document.getElementById('myChart').getContext('2d');
let chart;
$('#ticker').keypress(function (e) {
if (e.which === 13) { // Enter key pressed
const ticker = $(this).val().toUpperCase();
getStockData(ticker);
}
});
function getStockData(ticker) {
$.ajax({
url: `https://api.twelvedata.com/time_series?symbol=${ticker}&interval=1day&apikey=${apiKey}`,
method: 'GET',
success: function (data) {
// Handle successful response
const stockData = data.values.map(value => ({
x: new Date(value.datetime),
o: parseFloat(value.open),
h: parseFloat(value.high),
l: parseFloat(value.low),
c: parseFloat(value.close)
}));
createChart(stockData);
startRefreshInterval();
},
error: function (error) {
// Handle error
console.error('Error fetching stock data:', error);
}
});
}
function createChart(stockData) {
if (chart) {
chart.destroy();
}
chart = new Chart(chartCanvas, {
type: 'candlestick',
data: {
datasets: [{
label: 'Stock Price',
data: stockData,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 1
}]
},
options: {
// Chart configuration options
scales: {
x: {
type: 'time',
time: {
unit: 'day'
}
},
y: {
beginAtZero: true
}
},
plugins: {
tooltip: {
callbacks: {
label: function (context) {
const label = context.dataset.label || '';
const dataPoint = context.parsed;
return `${label}: ${dataPoint.y}`;
}
}
},
annotation: {
annotations: {
verticalLine: {
type: 'line',
scaleID: 'x',
xValue: null,
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 2
}
}
},
}
},
});
chart.options.plugins.annotation.annotations.verticalLine.label = {
enabled: false,
content: 'Loading...',
position: 'top'
};
chart.options.onClick = function (event, active) {
const index = active[0].index;
const dataPoint = chart.data.datasets[0].data[index];
chart.options.plugins.annotation.annotations.verticalLine.xValue = dataPoint.time;
chart.options.plugins.annotation.annotations.verticalLine.label.content = `Date: ${dataPoint.time.toLocaleDateString()}<br>Open: ${dataPoint.open}<br>High: ${dataPoint.high}<br>Low: ${dataPoint.low}`;
chart.options.plugins.annotation.annotations.verticalLine.label.enabled = true;
chart.update();
};
}
function startRefreshInterval() {
const refreshRate = parseInt($('#refresh-rate').val());
setInterval(function () {
getStockData($('#ticker').val());
}, refreshRate * 60 * 1000);
const minValue = parseFloat($('#min-value').val());
const maxValue = parseFloat($('#max-value').val());
if (!isNaN(minValue) && stockData[stockData.length - 1].open < minValue) {
window.alert(`Stock price is below the minimum value of ${minValue}`);
}
if (!isNaN(maxValue) && stockData[stockData.length - 1].open > maxValue) {
window.alert(`Stock price is above the maximum value of ${maxValue}`);
}
}
});
Google Gemini final webpage
The picture below is the result after all the previous issues fixed:
ChatGPT 4o
This time, I tried using ChatGPT to achieve the same result.
I did a small tweak to the prompt:
Instead of asking the apiKey
of being in an external file, it’s better for demo purposes to have a password input field, this removes the burden of having to manage a sensitive file.
create `html` and `javascript` website:
- use bootstrap 5 and jquery.
- it should have the following input files at the left top using css classes: `form-control d-inline ms-2` and `max-width: 200px`.
- The first input field is `ticker` and it represents a stock ticker.
- The second field should be `refresh-rate` and it represents the time to retrieve the stocks. it should be filled with number 5.
- The third field is `min-value` and it represents an alarm if the latest stock price is under this value.
- The fourth field is `max-value` and it represents an alarm if the latest stock price is above this value.
- The fifth field of password type is `api-key` and it represents the `twelvedata` api key.
- get the stock names and values from `twelvedata`.
- the `ticker` should support suggestions with the names from `twelvedata` api endpoint `/stocks`.
- after the user fills the `ticker` field, and presses `enter` key, check if it matches a stock name, if it does, get the stock values.
- after retrieving the stock prices, plot a `candlestick` type chart.
- each candlestick has at the top `high` value, at the bottom the `low` value.
- plot a linear chart for the `open` values.
- display an `X` axis, the labels for the date, and `Y` axis, the labels for the stock price.
- if the user clicks on the chart, display a vertical bar at that position and display a label with the date and open,high,low of the stock price.
- the stocks retrieval and chart should be updated every `refresh-rate` minute.
- if `min-value` field is a valid number, and the most recent open is below that value, it should do a `window.alert` instructing the user that the value is below `min-value`.
- if `max-value` field is a valid number, and the most recent open is above that value, it should do a `window.alert` instructing the user that the value is above `max-value`.
ChatGPT chatbox response
Just like Google Gemini it provided a partial javascript implementation, but instead of asking for remaining, I just wanted to see a working solution.
Therefore, the response below is less complete than the previous one.
The index.html
file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stock Price Monitor</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
<style>
.max-width-200 {
max-width: 200px;
}
</style>
</head>
<body>
<div class="container mt-3">
<div class="row">
<div class="col">
<input type="text" id="ticker" class="form-control d-inline ms-2 max-width-200" placeholder="Ticker">
<input type="number" id="refresh-rate" class="form-control d-inline ms-2 max-width-200" placeholder="Refresh Rate" value="5">
<input type="number" id="min-value" class="form-control d-inline ms-2 max-width-200" placeholder="Min Value">
<input type="number" id="max-value" class="form-control d-inline ms-2 max-width-200" placeholder="Max Value">
<input type="password" id="api-key" class="form-control d-inline ms-2 max-width-200" placeholder="API Key">
</div>
</div>
<div class="row mt-3">
<div class="col">
<div id="chart-container"></div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-chart-financial/dist/chartjs-chart-financial.min.js"></script>
</body>
</html>
The
script.js
file:<script>
$(document).ready(function() {
const apiKey = $('#api-key').val();
const refreshRate = $('#refresh-rate').val() * 60 * 1000;
let intervalId;
$('#ticker').on('keypress', function(e) {
if (e.which === 13) {
const ticker = $(this).val();
checkTicker(ticker);
}
});
function checkTicker(ticker) {
$.ajax({
url: `https://api.twelvedata.com/stocks`,
method: 'GET',
data: { symbol: ticker, apikey: apiKey },
success: function(response) {
if (response.data.length > 0) {
startRetrievingStockData(ticker);
} else {
alert('Ticker not found.');
}
}
});
}
function startRetrievingStockData(ticker) {
clearInterval(intervalId);
retrieveStockData(ticker);
intervalId = setInterval(() => retrieveStockData(ticker), refreshRate);
}
function retrieveStockData(ticker) {
$.ajax({
url: `https://api.twelvedata.com/time_series`,
method: 'GET',
data: {
symbol: ticker,
interval: '1min',
apikey: apiKey
},
success: function(response) {
if (response.status === 'ok') {
plotChart(response.values);
checkAlarms(response.values[0].open);
} else {
alert('Failed to retrieve stock data.');
}
}
});
}
function plotChart(data) {
const ctx = document.getElementById('chart-container').getContext('2d');
const candlestickData = data.map(item => ({
x: new Date(item.datetime),
o: parseFloat(item.open),
h: parseFloat(item.high),
l: parseFloat(item.low),
c: parseFloat(item.close)
}));
const chart = new Chart(ctx, {
type: 'candlestick',
data: {
datasets: [{
label: 'Stock Data',
data: candlestickData
}]
},
options: {
scales: {
x: {
type: 'time',
time: {
unit: 'minute'
}
},
y: {
beginAtZero: false
}
}
}
});
}
function checkAlarms(latestOpen) {
const minValue = $('#min-value').val();
const maxValue = $('#max-value').val();
if (minValue && latestOpen < minValue) {
window.alert(`The latest open value ${latestOpen} is below the minimum value ${minValue}`);
}
if (maxValue && latestOpen > maxValue) {
window.alert(`The latest open value ${latestOpen} is above the maximum value ${maxValue}`);
}
}
});
</script>
ChatGPT chatbox response issues
Unlike Google Gemini which provided a file structure, and the html code separated from the javascript file, ChatGPT generated two files .html
and .js
which require to insert the javascript inside the .html file since it’s wrapped with a <script>
tags.
Comparing to Google Gemini:
- 👍️ It included the
chartjs-chart-financial
script, which is probably the hardest part to detect. - 👍️ It included the
.getContext('2d')
on thedocument.getElementById('chart-container')
.
Where did it failed (both issues were fixed on ChatGPT 5:
- 👎️ Gets the value of the
apiKey
right on$(document).ready
not giving time for the user to input theapi-key
. Fixed on ChatGPT 5. - 👎️ Uses
<div>
forchart-container
which doesn’t allows to.getContext(
, instead, it should have used a<canvas>
. Fixed on ChatGPT 5.
Although it provided the external script chartjs-chart-financial
, I had to dig into the chartjs-chart-financial example to understand the problem.
The correct scripts were:
<script src="https://cdn.jsdelivr.net/npm/luxon@3.4.4"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.3.1"></script>
<script src="https://www.chartjs.org/chartjs-chart-financial/chartjs-chart-financial.js" type="text/javascript"></script>
After these fixes, it was able to produce a candlestick chart.
It was far and beyond what I requested, it would require more research to make visual results useful, but, at this point, it was clear the limitation of both AI tools, so I decided to halt the process.
ChatGPT manually tweaked response
The end result in a single .html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Stock Price Monitor</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
<style>
.max-width-200 {
max-width: 200px;
}
</style>
</head>
<body>
<div class="container mt-3">
<div class="row">
<div class="col">
<input type="text" id="ticker" class="form-control d-inline ms-2 max-width-200" placeholder="Ticker">
<input type="number" id="refresh-rate" class="form-control d-inline ms-2 max-width-200" placeholder="Refresh Rate" value="5">
<input type="number" id="min-value" class="form-control d-inline ms-2 max-width-200" placeholder="Min Value">
<input type="number" id="max-value" class="form-control d-inline ms-2 max-width-200" placeholder="Max Value">
<input type="password" id="api-key" class="form-control d-inline ms-2 max-width-200" placeholder="API Key">
</div>
</div>
<div class="row mt-3">
<div class="col">
<canvas id="chart-container"></canvas>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luxon@3.4.4"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.3.1"></script>
<script src="https://www.chartjs.org/chartjs-chart-financial/chartjs-chart-financial.js" type="text/javascript"></script>
<script>
$(document).ready(function() {
const apiKey = $('#api-key').val();
const refreshRate = $('#refresh-rate').val() * 60 * 1000;
let intervalId;
$('#ticker').on('keypress', function(e) {
if (e.which === 13) {
const ticker = $(this).val();
checkTicker(ticker);
}
});
function checkTicker(ticker) {
const apiKey = $('#api-key').val();
$.ajax({
url: `https://api.twelvedata.com/stocks`,
method: 'GET',
data: { symbol: ticker, apikey: apiKey },
success: function(response) {
if (response.data.length > 0) {
startRetrievingStockData(ticker);
} else {
alert('Ticker not found.');
}
}
});
}
function startRetrievingStockData(ticker) {
clearInterval(intervalId);
retrieveStockData(ticker);
intervalId = setInterval(() => retrieveStockData(ticker), refreshRate);
}
function retrieveStockData(ticker) {
const apiKey = $('#api-key').val();
$.ajax({
url: `https://api.twelvedata.com/time_series`,
method: 'GET',
data: {
symbol: ticker,
interval: '1min',
apikey: apiKey
},
success: function(response) {
if (response.status === 'ok') {
plotChart(response.values);
checkAlarms(response.values[0].open);
} else {
alert('Failed to retrieve stock data.');
}
}
});
}
function plotChart(data) {
const ctx = document.getElementById('chart-container').getContext('2d');
const candlestickData = data.map(item => ({
x: new Date(item.datetime),
o: parseFloat(item.open),
h: parseFloat(item.high),
l: parseFloat(item.low),
c: parseFloat(item.close)
}));
const chart = new Chart(ctx, {
type: 'candlestick',
data: {
datasets: [{
label: 'Stock Data',
data: candlestickData
}]
},
options: {
scales: {
x: {
type: 'time',
time: {
unit: 'minute'
}
},
y: {
beginAtZero: false
}
}
}
});
}
function checkAlarms(latestOpen) {
const minValue = $('#min-value').val();
const maxValue = $('#max-value').val();
if (minValue && latestOpen < minValue) {
window.alert(`The latest open value ${latestOpen} is below the minimum value ${minValue}`);
}
if (maxValue && latestOpen > maxValue) {
window.alert(`The latest open value ${latestOpen} is above the maximum value ${maxValue}`);
}
}
});
</script>
</body>
</html>
ChatGPT final webpage
The picture below is the result after all the previous issues fixed:
ChatGPT 5
The unofficial version of ChatGPT 5 became available after the initial release of the article.
The code generated on the new version no longer has the problem with the <canvas>
and apiKey
described in the section above, however, still wasn’t able to produce a fully functional candlestick
chart.
Conclusion
- 👎️ None of the AI tools used, Google Gemini and ChatGPT, were able to provide a working solution. Even after multiple fixes, the final result was still garbled with the charts providing unusable results.
- 👍️ ChatGPT added the link to
chartjs-chart-financial
, although it wasn’t working, it was a fundamental point sincechartjs
doesn’t support candlestick chart type. Using only Google Gemini, the user would believe that the output was completely useless, while with this link, after some research, I was able to display something on the chart. - 👍 Both AI tools were able to retrieve the stock names and prices from “twelvedata” since their API is well documented.
- 👍 Both AI tools were able to generate well-formed html and javascript code.
- 👍 Both AI tools were able to generate basic chart code, which could have been due chartjs.org provides documentation and examples.
- 👎️ Both AI tools didn’t produce a correct candlestick chart, which could have been due the
chartjs-chart-financial
plugin doesn’t provide proper documentation.
In comparison, ChatGPT produced less errors with a single prompt and a better solution than Google Gemini.