Анализ биржевых данных
Извлечение и первичный анализ биржевых котировок
Введение
В данной работе представлено выполнение извлечения и первичного анализа биржевых котировок акций с использованием библиотеки YFinance, предоставляющей программный доступ к данным финансового портала Yahoo Finance.
Yahoo Finance – один из крупнейших публичных финансовых порталов, аккумулирующий биржевую информацию по акциям, фондам, валютам и товарным активам со множества мировых площадок (NASDAQ, NYSE, AMEX, ARCA, BATS). Библиотека YFinance позволяет обращаться к этим данным напрямую из кода, что делает её удобным инструментом для учебных и аналитических задач.
В данном примере рассмотрим котировки акций Apple Inc. (AAPL) за один год с шагом в один торговый день. На их основе рассчитаем и визуализируем ряд ключевых характеристик:
- Динамика цены – график изменения цены закрытия во времени, позволяющий увидеть общий тренд инструмента, периоды роста и падения, а также амплитуду колебаний.
- Объём торгов – количество акций, купленных и проданных за интервал. Показатель отражает активность участников рынка и ликвидность инструмента.
- Доходность – относительное изменение цены за один интервал; показывает, какую долю от вложенной суммы принёс или потерял инвестор за один шаг.
- Волатильность – мера изменчивости доходности, обычно измеряемая как стандартное отклонение. Чем выше волатильность, тем сильнее колеблется цена и тем выше риск инструмента.
- Накопленная доходность – итоговый результат удержания акции с начала периода до текущего момента; позволяет сравнить несколько инструментов на одном графике.
- Просадка – показывает, насколько текущая цена ниже своего исторического максимума, и характеризует глубину падения и максимальную потерю для инвестора.
Дополнительно сравним накопленную доходность нескольких крупных технологических компаний (AAPL, MSFT, NVDA, AMZN), что позволит оценить относительную эффективность выбранного инструмента.
Цель работы - продемонстрировать полный цикл количественного анализа акции: от получения котировок из внешнего источника до расчёта и визуализации метрик, характеризующих её доходность, риск и инвестиционную привлекательность.
Присоединение библиотек
Для данной работы нам понадобятся следующие библиотеки:
YFinance– получение биржевых данных из Yahoo Finance;DataFrames– работа с табличными данными;Statistics– работа с табличными данными;Dates– работа с датой и временем;Colors– работа с цветами при визуализации.
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
Выбор биржи и отображение списка акций
Библиотека YFinance позволяет извлечь данные котировок акций из следующих бирж:
- AMEX – American Stock Exchange (Американская фондовая биржа)
- ARCA – биржа Archipelago Exchange
- BATS – биржа Better Alternative Trading System
- NASDAQ – National Association of Securities Dealers Automated Quotations (автоматизированная система котировок Национальной ассоциации дилеров по ценным бумагам)
- NYSE – New York Stock Exchange (Нью-Йоркская фондовая биржа)
Для нашего исследования, выберем биржу NASDAQ и отобразим краткий список наименований акций, торгуемых на данной бирже. Вы можете отобразить полный список с помощью команды print(акции).
акции = get_all_symbols("NASDAQ")
display(акции)
#print(акции)
Выбор акций, периода и интервала
Выберем период, интервал, и компанию, котировки акций которой будем исследовать.
Период range – это промежуток времени, отсчитываемый от настоящего момента (момента публикации данного примера или момента запуска скрипта) в прошлое, за который загружаются доступные биржевые данные. Период задаётся целым числом и обозначением единицы времени. Конечная точка периода определяется последними доступными данными, обычно соответствующими последнему завершённому торговому интервалу. Например: последние 7 дней, 3 месяца или 2 года.
Интервал interval – это шаг, с которым данные представлены внутри выбранного периода: например, 1 минута, 1 час или 1 день.
Цена акции фиксируется на момент закрытия каждого выбранного интервала. Например, при интервале 1 день это цена закрытия торгового дня, а при интервале 5 минут – цена закрытия каждого пятиминутного интервала.
Период задаётся следующим образом:
-
m– минуты:30m– 30 минут; -
d– дни:7d– 7 дней; -
mo– месяцы:3mo– 3 месяца; -
y– годы:2y– 2 года; -
ytd– с начала текущего года; -
max– максимально доступный период.
Интервал можно выбирать только из фиксированного списка: 1m, 2m, 5m, 15m, 30m, 60m, 90m, 1h, 1d, 5d, 1wk, 1mo, 3mo. При этом период является более гибким: например, период 7m означает 7 минут, потому что для range можно указывать произвольное число минут (дней, месяцев, лет).
В качестве объекта исследования выберем акции компании Apple Inc. (AAPL).
акция = "AAPL"
период = "1y"
интервал = "1d"
println("Акция: ", акция, "\nПериод: ", период, "\nИнтервал: ", интервал)
Извлечение исходных данных
Выполним извлечение значений биржевых котировок в соответствии с выбранной акцией, периодом и интервалом. Данные о дате и времени представлены в соответствии с часовым поясом UTC+0.
данные = get_prices(акция, range = период, interval = интервал)
println("Данные извлечены\nКоличество наблюдений: ", length(данные["close"]))
Преобразование данных в DataFrame
Преобразуем полученные данные в DataFrame и преобразуем данные о дате и времени в UTC+3. Теперь дата и время будут соответствовать часовому поясу Москвы.
df = DataFrame(данные)
df.timestamp = df.timestamp .+ Hour(3)
display(df)
Основные биржевые характеристики
Отобразим основные биржевые характеристики акций исследуемой компании.
println("Акция: ", акция)
println("Начало периода: ", first(df.timestamp), " UTC+3")
println("Конец периода: ", last(df.timestamp), " UTC+3")
println("Количество интервалов: ", nrow(df))
println("\nНачальная цена: ", round(first(df.close), digits=2), " \$")
println("Конечная цена: ", round(last(df.close), digits=2), " \$")
println("Минимум: ", round(minimum(df.close), digits=2), " \$")
println("Максимум: ", round(maximum(df.close), digits=2), " \$")
Динамика цены
Построим график ценовой динамики акций за выбранный период.
plot(
df.timestamp,
df.close,
xlabel = "Дата и время",
ylabel = "Цена, \$",
title = "$акция – динамика цены",
label = "Цена",
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))
Объём торгов
Построим график объёма торгов в соответствии с выбранным периодом и интервалом.
plot(
df.timestamp,
df.vol,
xlabel = "Дата и время",
ylabel = "Количество акций",
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))
Доходность
Интервальная доходность рассчитывается по формуле:
где:
- – порядковый номер наблюдения;
- – цена, относительно которой считается прирост;
- – цена цена закрытия в следующем наблюдении.
Вычислим интервальную доходность и поместим вычисленные значения в новый столбец.
df.Доходность = [missing; diff(df.close) ./ df.close[1:end-1]]
display(df)
Вычислим среднюю доходность за интервал стандартное отклонение доходности.
доходности = skipmissing(df.Доходность)
println("Средняя интервальная доходность: ", round(mean(доходности) * 100, digits=3), "%")
println("Стандартное отклонение: ", round(std(доходности) * 100, digits=3), "%")
Построим график доходности.
plot(
df.timestamp,
df.Доходность .* 100,
xlabel = "Дата и время",
ylabel = "Доходность, %",
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])
Построим гистограмму распределения доходностей за выбранные интервалы.
histogram(
collect(доходности) .* 100,
bins = 40,
xlabel = "Доходность, %",
ylabel = "Количество",
title = "$акция – распределение интервальных доходностей",
label = false,
fillcolor = RGB(0/255, 198/255, 201/255) )
Волатильность
Определим период волатильности, указав количество интервалов.
период_волатильности = 20
Скользящая волатильность рассчитывается как стандартное отклонение доходностей в скользящем окне фиксированной длины. Построим график скользящей волатильности за выбранный период.
function скользящая_волатильность(x, окно)
[std(x[i-окно+1:i])
for i in окно:length(x)]
end
волатильность = скользящая_волатильность(collect(доходности), период_волатильности)
plot(
df.timestamp[21:end],
волатильность .* 100,
xlabel = "Дата и время",
ylabel = "Волатильность, %",
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) )
Накопленная доходность
Накопленная доходность рассчитывается как произведение множителей роста по всем интервалам:
где:
-
— порядковый номер интервала, для которого считается накопленная доходность.
-
— интервальная доходность на -м шаге.
Построим график накопленной доходности.
накопленная_доходность = cumprod(1 .+ collect(доходности))
plot(
df.timestamp[2:end],
(накопленная_доходность .- 1) .* 100,
xlabel = "Дата и время",
ylabel = "Доходность, %",
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 = "Начало")
Просадка
Просадка показывает, насколько текущая цена ниже своего исторического максимума, достигнутого к данному моменту:
где:
-
— порядковый номер наблюдения;
-
— цена закрытия в момент t;
-
— исторический максимум цены за промежуток от начала периода до момента t включительно: , где — индекс, который перебирает все значения от до .
цены = df.close
просадка = цены ./ accumulate(max, цены) .- 1
println("Максимальная просадка: ", round(minimum(просадка) * 100, digits=2), "%")
Построим график просадки за выбранный период.
plot(
df.timestamp,
просадка .* 100,
xlabel = "Дата и время",
ylabel = "Просадка, %",
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 = "")
Итоговые характеристики акций
Отобразим итоговые характеристики акций выбранной компании.
итог = 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(итог)
Сравнение с другими акциями
Выполним извлечение котировок акций AAPL, MSFT, NVDA, AMZN; и построим график сравнения их накопленной доходности.
акции = ["AAPL", "MSFT", "NVDA", "AMZN"]
данные_акций = Dict()
for акция in акции
данные_акций[акция] = get_prices(акция, range = период, interval = интервал)
end
график = plot(xlabel = "Дата и время", ylabel = "Накопленная доходность, %",
title = "Сравнение акций", 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(график)
Заключение
В данной примере выполнен полный цикл количественного анализа акций на основе данных Yahoo Finance, полученных средствами библиотеки YFinance. Построены графики динамики цены, объёма торгов, интервальной доходности, её распределения, скользящей волатильности, накопленной доходности и просадки. Рассчитаны итоговые характеристики, включая доходность за период, среднюю интервальную доходность, волатильность и максимальную просадку. Дополнительно выполнено сравнение накопленной доходности между акциями различных компаний.
Результаты работы имеют практическую ценность в различных областях, например:
- в инвестиционном анализе – для оценки доходности и риска инструмента и его сравнения с аналогами;
- в управлении портфелем – для контроля риска и принятия решений о приведении структуры инвестиционного портфеля к заданному целевому соотношению активов;
- в исследованиях – подход легко переносится на другие акции, периоды и интервалы.
Полученные биржевые котировки могут являться исходными данными для более глубокого финансового анализа. Вы можете выбрать другие акции, периоды и интервалы для дальнейших исследований. Таким образом, набор методов, реализованный в данном примере, позволяет получить содержательные выводы о поведении финансового инструмента и служит удобной отправной точкой для более серьёзных исследований.