Extraction and primary analysis of stock quotes
Introduction
This paper presents the extraction and primary analysis of stock market quotations using the YFinance library, which provides programmatic access to data from the Yahoo Finance financial portal.
Yahoo Finance* is one of the largest public financial portals that accumulates exchange information on stocks, funds, currencies and commodity assets from many global platforms (NASDAQ, NYSE, AMEX, ARCA, BATS). Library YFinance It allows you to access this data directly from the code, which makes it a convenient tool for educational and analytical tasks.
In this example, let's look at the stock quotes of Apple Inc. (AAPL) for one year in increments of one trading day. Based on them, we will calculate and visualize a number of key characteristics.:
- Price dynamics – a chart of the closing price changes over time, allowing you to see the overall trend of the instrument, periods of growth and fall, as well as the amplitude of fluctuations.
- Trading volume – the number of shares bought and sold during the interval. The indicator reflects the activity of market participants and the liquidity of the instrument.
- Profitability is the relative price change over one interval; it shows how much of the invested amount the investor has gained or lost in one step.
- Volatility is a measure of the variability of returns, usually measured as a standard deviation. The higher the volatility, the more the price fluctuates and the higher the risk of the instrument.
- Accumulated profitability is the final result of holding a stock from the beginning of the period to the current moment; it allows you to compare several instruments on the same chart.
- Drawdown – shows how much the current price is below its historical maximum, and characterizes the depth of the fall and the maximum loss for the investor.
Additionally, we will compare the accumulated profitability of several large technology companies (AAPL, MSFT, NVDA, AMZN), which will allow us to assess the relative effectiveness of the chosen tool.
The purpose of the work is to demonstrate the full cycle of quantitative analysis of a stock: from obtaining quotes from an external source to calculating and visualizing metrics characterizing its profitability, risk and investment attractiveness.
Joining libraries
For this work, we will need the following libraries:
YFinance– getting stock data from Yahoo Finance;DataFrames– working with tabular data;Statistics– working with tabular data;Dates– working with date and time;Colors– working with colors in visualization.
for lib in ["YFinance", "DataFrames", "Statistics", "Dates", "Colors"]
try
eval(Meta.parse("using $lib"))
catch ex
import Pkg
Pkg.add(lib)
eval(Meta.parse("using $lib"))
end
end
Selecting an exchange and displaying a list of stocks
Library YFinance allows you to extract stock quotation data from the following exchanges:
- AMEX – American Stock Exchange
- ARCA – Archipelago Exchange
- BATS – Better Alternative Trading System Exchange
- NASDAQ – National Association of Securities Dealers Automated Quotations
- NYSE – New York Stock Exchange
For our research, let's select the NASDAQ stock exchange and display a short list of stock names traded on this exchange. You can display the full list using the command print(акции).
акции = get_all_symbols("NASDAQ")
display(акции)
# print(promotions)
Selection of stocks, period and interval
Let's choose a period, an interval, and a company whose stock prices we will investigate.
Period range – this is the period of time counted from the present moment (the moment of publication of this example or the moment of script launch) to the past, during which the available exchange data is loaded. The period is set as an integer and a time unit designation. The end point of the period is determined by the latest available data, usually corresponding to the last completed trading interval. For example: the last 7 days, 3 months, or 2 years.
Interval interval – this is the step with which the data is presented within the selected period: for example, 1 minute, 1 hour or 1 day.
The share price is fixed at the time of closing of each selected interval. For example, with an interval of 1 day, this is the closing price of the trading day, and with an interval of 5 minutes, it is the closing price of each five–minute interval.
The period is set as follows:
-
m– minutes:30m– 30 minutes; -
d– days:7d– 7 days; -
mo– months:3mo– 3 months; -
y– years:2y– 2 years old; -
ytd– since the beginning of this year; -
max– the maximum available period.
The interval can only be selected from a fixed list.: 1m, 2m, 5m, 15m, 30m, 60m, 90m, 1h, 1d, 5d, 1wk, 1mo, 3mo. However, the period is more flexible: for example, the period 7m it means 7 minutes, because for range you can specify any number of minutes (days, months, years).
Let's choose shares of Apple Inc. (AAPL) as the object of research.
акция = "AAPL"
период = "1y"
интервал = "1d"
println("Stock: ", акция, "\nПериод: ", период, "\nИнтервал: ", интервал)
Extracting the source data
We will extract the values of stock quotes in accordance with the selected stock, period and interval. The date and time data are presented in accordance with the UTC+0 time zone.
данные = get_prices(акция, range = период, interval = интервал)
println("Данные извлечены\nКоличество наблюдений: ", length(данные["close"]))
Converting data to a DataFrame
Converting the received data to a DataFrame and converting the date and time data to UTC+3. The date and time will now correspond to the Moscow time zone.
df = DataFrame(данные)
df.timestamp = df.timestamp .+ Hour(3)
display(df)
The main stock characteristics
Let's display the main stock characteristics of the shares of the company under study.
println("Stock: ", акция)
println("Beginning of the period: ", first(df.timestamp), " UTC+3")
println("End of the period: ", last(df.timestamp), " UTC+3")
println("Number of intervals: ", nrow(df))
println("\nНачальная цена: ", round(first(df.close), digits=2), " \$")
println("Final price: ", round(last(df.close), digits=2), " \$")
println("Minimum: ", round(minimum(df.close), digits=2), " \$")
println("Maximum: ", round(maximum(df.close), digits=2), " \$")
Price dynamics
Let's plot the price dynamics of stocks for the selected period.
plot(
df.timestamp,
df.close,
xlabel = "Date and time",
ylabel = "Цена, \$",
title = "$акция – динамика цены",
label = "Price",
linewidth = 2.2,
legend = false,
hover = ["Дата и время: $(Dates.format(df.timestamp[i], "dd.mm.yyyy HH:MM")) UTC+3 | Цена: $(round(df.close[i], digits=2)) \$"
for i in 1:length(df.close)],
linecolor = RGB(0/255, 198/255, 201/255))
Trading volume
Let's plot the trading volume chart according to the selected period and interval.
plot(
df.timestamp,
df.vol,
xlabel = "Date and time",
ylabel = "Number of shares",
title = "$акция – объём торгов",
label = false,
linewidth = 2.2,
legend = false,
hover = ["Дата и время: $(Dates.format(df.timestamp[i], "dd.mm.yyyy HH:MM")) UTC+3 | " * "$(round(Int, df.vol[i])) акций"
for i in eachindex(df.vol)], linecolor = RGB(1, 117/255, 56/255))
Profitability
The interval yield is calculated using the formula:
where:
- – serial number of the observation;
- – the price relative to which the increase is calculated;
- – the price is the closing price in the next observation.
Calculate the interval return and put the calculated values in a new column.
df.Доходность = [missing; diff(df.close) ./ df.close[1:end-1]]
display(df)
Calculate the average return over the standard deviation of return interval.
доходности = skipmissing(df.Доходность)
println("Average interval profitability: ", round(mean(доходности) * 100, digits=3), "%")
println("Standard deviation: ", round(std(доходности) * 100, digits=3), "%")
Let's build a yield graph.
plot(
df.timestamp,
df.Доходность .* 100,
xlabel = "Date and time",
ylabel = "Profitability, %",
title = "$акция – интервальные доходности",
label = false,
linewidth = 2,
legend = false,
hover = ["Дата и время: $(Dates.format(df.timestamp[i], "dd.mm.yyyy HH:MM")) UTC+3 | Доходность: $(100*round(df.Доходность[i], digits=5))%"
for i in 1:length(df.Доходность)],
linecolor = RGB(221/255, 128/255, 201/204) )
hline!([0])
Let's build a histogram of the distribution of yields for the selected intervals.
histogram(
collect(доходности) .* 100,
bins = 40,
xlabel = "Profitability, %",
ylabel = "Quantity",
title = "$акция – распределение интервальных доходностей",
label = false,
fillcolor = RGB(0/255, 198/255, 201/255) )
Volatility
Let's define the period of volatility by specifying the number of intervals.
период_волатильности = 20
Rolling volatility is calculated as the standard deviation of returns in a fixed-length sliding window. Let's plot the moving volatility chart for the selected period.
function скользящая_волатильность(x, окно)
[std(x[i-окно+1:i])
for i in окно:length(x)]
end
волатильность = скользящая_волатильность(collect(доходности), период_волатильности)
plot(
df.timestamp[21:end],
волатильность .* 100,
xlabel = "Date and time",
ylabel = "Volatility, %",
title = "$акция – волатильность за период",
label = false,
linewidth = 2,
legend = false,
hover = ["Дата и время: $(Dates.format(df.timestamp[i+период_волатильности], "dd.mm.yyyy HH:MM")) UTC+3 | Волатильность: $(round(100*волатильность[i], digits=4))%"
for i in 1:length(волатильность)],
linecolor = RGB(148/255, 0/255, 211/255) )
Accumulated profitability
The accumulated return is calculated as the product of the growth multipliers for all intervals:
where:
-
— the sequential number of the interval for which the accumulated profitability is calculated.
-
— interval profitability on - Mmm.
Let's build a graph of accumulated profitability.
накопленная_доходность = cumprod(1 .+ collect(доходности))
plot(
df.timestamp[2:end],
(накопленная_доходность .- 1) .* 100,
xlabel = "Date and time",
ylabel = "Profitability, %",
title = "$акция – накопленная доходность",
label = false,
linewidth = 2,
legend = false,
hover = ["Дата и время: $(Dates.format(df.timestamp[i], "dd.mm.yyyy HH:MM")) UTC+3 | Доходность: $(round(100*(накопленная_доходность[i] - 1), digits=3))%"
for i in 1:length(накопленная_доходность)],
linecolor = RGB(245/255, 64/255, 33/255) )
hline!([0], label = "Beginning")
Drawdown
The drawdown shows how much the current price is below its historical maximum reached so far.:
where:
-
— serial number of the observation;
-
— closing price at time t;
-
— the historical maximum of the price for the period from the beginning of the period to the moment t inclusive: , where — an index that iterates over all values from before .
цены = df.close
просадка = цены ./ accumulate(max, цены) .- 1
println("Maximum drawdown: ", round(minimum(просадка) * 100, digits=2), "%")
Let's build a drawdown chart for the selected period.
plot(
df.timestamp,
просадка .* 100,
xlabel = "Date and time",
ylabel = "Drawdown, %",
title = "$акция – просадка за период",
label = false,
linewidth = 2,
legend = false,
hover = ["Дата и время: $(Dates.format(df.timestamp[i], "dd.mm.yyyy HH:MM")) UTC+3 | Просадка: $(100*round(просадка[i], digits=4))%"
for i in 1:length(просадка)],
linecolor = RGB(48/255, 98/255, 107/255) )
hline!([0], label = "")
Summary characteristics of the shares
Let's display the final characteristics of the shares of the selected company.
итог = DataFrame(
Показатель = [
"Начальная цена",
"Конечная цена",
"Минимальная цена",
"Максимальная цена",
"Доходность за период",
"Средняя интервальная доходность",
"Волатильность доходности",
"Максимальная просадка"],
Значение = [
first(df.close),
last(df.close),
minimum(df.close),
maximum(df.close),
(last(df.close) / first(df.close) - 1) * 100,
mean(доходности) * 100,
std(доходности) * 100,
minimum(просадка) * 100])
display(итог)
Comparison with other stocks
Let's extract stock quotes from AAPL, MSFT, NVDA, AMZN; and plot a comparison graph of their accumulated returns.
акции = ["AAPL", "MSFT", "NVDA", "AMZN"]
данные_акций = Dict()
for акция in акции
данные_акций[акция] = get_prices(акция, range = период, interval = интервал)
end
график = plot(xlabel = "Date and time", ylabel = "Accumulated profitability, %",
title = "Stock Comparison", legend = :topleft)
for акция in акции
данные_текущие = данные_акций[акция]
даты = данные_текущие["timestamp"]
цены = данные_текущие["close"]
доходность = (цены ./ first(цены) .- 1) .* 100
plot!(график, даты, доходность, label = акция, linewidth = 2,
hover = ["Дата и время: $(Dates.format(даты[i], "dd.mm.yyyy HH:MM")) UTC+3 | Доходность: $(round(доходность[i], digits=2))%"
for i in 1:length(доходность)],)
end
hline!( график, [0], label = "", linestyle = :dash )
display(график)
Conclusion
In this example, a full cycle of quantitative stock analysis is performed based on Yahoo Finance data obtained from the library. YFinance. Graphs of price dynamics, trading volume, interval profitability, its distribution, rolling volatility, accumulated profitability and drawdown are constructed. The final characteristics are calculated, including profitability for the period, average interval profitability, volatility and maximum drawdown. Additionally, a comparison of the accumulated returns between shares of different companies was performed.
The results of the work have practical value in various fields, for example:
- in investment analysis – to assess the profitability and risk of an instrument and compare it with its analogues;
- in portfolio management – for risk control and decision-making on bringing the structure of the investment portfolio to a given target asset ratio;
- In research, the approach is easily transferred to other stocks, periods, and intervals.
The resulting stock quotes can be the source data for a deeper financial analysis. You can select other promotions, periods, and intervals for further research. Thus, the set of methods implemented in this example allows us to draw meaningful conclusions about the behavior of a financial instrument and serves as a convenient starting point for more serious research.