Документация Engee
Notebook

Извлечение и первичный анализ биржевых котировок

Введение

В данной работе представлено выполнение извлечения и первичного анализа биржевых котировок акций с использованием библиотеки 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 – работа с цветами при визуализации.
In [ ]:
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(акции).

In [ ]:
акции = get_all_symbols("NASDAQ")
display(акции)
#print(акции)
5622-element Vector{String}:
 "AAAP"
 "AACG"
 "AACI"
 "AACIU"
 "AACIW"
 "AACO"
 "AACOU"
 "AACOW"
 "AACP"
 "AACPR"
 "AACPU"
 "AACPW"
 "AADR"
 ⋮
 "ZSQR"
 "ZSTK"
 "ZTEN"
 "ZTG"
 "ZTOP"
 "ZTRE"
 "ZTWO"
 "ZUMZ"
 "ZURA"
 "ZVRA"
 "ZYBT"
 "ZYME"

Выбор акций, периода и интервала

Выберем период, интервал, и компанию, котировки акций которой будем исследовать.

Период 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).

In [ ]:
акция = "AAPL"
период = "1y"
интервал = "1d"
println("Акция: ", акция, "\nПериод: ", период, "\nИнтервал: ", интервал)
Акция: AAPL
Период: 1y
Интервал: 1d

Извлечение исходных данных

Выполним извлечение значений биржевых котировок в соответствии с выбранной акцией, периодом и интервалом. Данные о дате и времени представлены в соответствии с часовым поясом UTC+0.

In [ ]:
данные = get_prices(акция, range = период, interval = интервал)
println("Данные извлечены\nКоличество наблюдений: ", length(данные["close"]))
Данные извлечены
Количество наблюдений: 251

Преобразование данных в DataFrame

Преобразуем полученные данные в DataFrame и преобразуем данные о дате и времени в UTC+3. Теперь дата и время будут соответствовать часовому поясу Москвы.

In [ ]:
df = DataFrame(данные)
df.timestamp = df.timestamp .+ Hour(3)
display(df)
251×8 DataFrame
226 rows omitted
Rowtickertimestampopenhighlowcloseadjclosevol
StringDateTimeFloat64Float64Float64Float64Float64Float64
1AAPL2025-10-09T16:30:00256.861257.05252.208254.04253.1053.8181e7
2AAPL2025-10-10T16:30:00254.002255.436243.102245.27244.3676.17709e7
3AAPL2025-10-13T16:30:00248.462248.771244.656247.66246.7493.80025e7
4AAPL2025-10-14T16:30:00245.692247.934243.799247.77246.8583.53474e7
5AAPL2025-10-15T16:30:00248.572250.893246.559249.34248.4223.37689e7
6AAPL2025-10-16T16:30:00247.336248.123244.228247.45246.5393.96306e7
7AAPL2025-10-17T16:30:00247.107252.447246.36252.29251.3614.89661e7
8AAPL2025-10-20T16:30:00254.948263.407254.689262.24261.2759.015e7
9AAPL2025-10-21T16:30:00260.916264.314260.866262.77261.8034.6524e7
10AAPL2025-10-22T16:30:00261.683261.883254.49258.45257.4994.48496e7
11AAPL2025-10-23T16:30:00258.983259.661257.06259.58258.6253.26343e7
12AAPL2025-10-24T16:30:00260.229263.158258.226262.82261.8533.81129e7
13AAPL2025-10-27T16:30:00263.905268.13263.676268.81267.8214.4723e7
⋮⋮⋮⋮⋮⋮⋮⋮⋮
240AAPL2026-09-23T16:30:00341.08341.8335.5337.02337.023.16588e7
241AAPL2026-09-24T16:30:00336.72338.91334.3335.92335.922.47331e7
242AAPL2026-09-25T16:30:00336.04341.67334.53341.07341.073.00025e7
243AAPL2026-09-28T16:30:00340.37342.99338.04338.4338.43.28208e7
244AAPL2026-09-29T16:30:00336.97337.09328.7329.4329.43.8478e7
245AAPL2026-09-30T16:30:00330.8339.5330.14333.02333.024.99886e7
246AAPL2026-10-01T16:30:00330.0332.48325.81330.32330.323.63063e7
247AAPL2026-10-02T16:30:00333.26334.54330.61333.69333.693.32786e7
248AAPL2026-10-05T16:30:00332.82336.21331.65332.89332.893.44009e7
249AAPL2026-10-06T16:30:00332.28334.38330.62333.63333.633.0449e7
250AAPL2026-10-07T16:30:00336.96338.67332.78336.67336.673.41479e7
251AAPL2026-10-08T16:30:00336.82341.57335.9340.42340.423.52799e7

Основные биржевые характеристики

Отобразим основные биржевые характеристики акций исследуемой компании.

In [ ]:
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), " \$")
Акция: AAPL
Начало периода: 2025-10-09T16:30:00 UTC+3
Конец периода:  2026-10-08T16:30:00 UTC+3
Количество интервалов: 251

Начальная цена: 254.04 $
Конечная цена:  340.42 $
Минимум:         245.27 $
Максимум:        341.07 $

Динамика цены

Построим график ценовой динамики акций за выбранный период.

In [ ]:
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))
Out[0]:

Объём торгов

Построим график объёма торгов в соответствии с выбранным периодом и интервалом.

In [ ]:
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))
Out[0]:

Доходность

Интервальная доходность рассчитывается по формуле:

где:

  • – порядковый номер наблюдения;
  • – цена, относительно которой считается прирост;
  • – цена цена закрытия в следующем наблюдении.

Вычислим интервальную доходность и поместим вычисленные значения в новый столбец.

In [ ]:
df.Доходность = [missing; diff(df.close) ./ df.close[1:end-1]]
display(df)
251×9 DataFrame
226 rows omitted
RowtickertimestampopenhighlowcloseadjclosevolДоходность
StringDateTimeFloat64Float64Float64Float64Float64Float64Float64?
1AAPL2025-10-09T16:30:00256.861257.05252.208254.04253.1053.8181e7missing
2AAPL2025-10-10T16:30:00254.002255.436243.102245.27244.3676.17709e7-0.0345221
3AAPL2025-10-13T16:30:00248.462248.771244.656247.66246.7493.80025e70.00974436
4AAPL2025-10-14T16:30:00245.692247.934243.799247.77246.8583.53474e70.00044416
5AAPL2025-10-15T16:30:00248.572250.893246.559249.34248.4223.37689e70.00633649
6AAPL2025-10-16T16:30:00247.336248.123244.228247.45246.5393.96306e7-0.00758001
7AAPL2025-10-17T16:30:00247.107252.447246.36252.29251.3614.89661e70.0195595
8AAPL2025-10-20T16:30:00254.948263.407254.689262.24261.2759.015e70.0394387
9AAPL2025-10-21T16:30:00260.916264.314260.866262.77261.8034.6524e70.00202104
10AAPL2025-10-22T16:30:00261.683261.883254.49258.45257.4994.48496e7-0.0164401
11AAPL2025-10-23T16:30:00258.983259.661257.06259.58258.6253.26343e70.00437212
12AAPL2025-10-24T16:30:00260.229263.158258.226262.82261.8533.81129e70.0124818
13AAPL2025-10-27T16:30:00263.905268.13263.676268.81267.8214.4723e70.0227912
⋮⋮⋮⋮⋮⋮⋮⋮⋮⋮
240AAPL2026-09-23T16:30:00341.08341.8335.5337.02337.023.16588e7-0.00803535
241AAPL2026-09-24T16:30:00336.72338.91334.3335.92335.922.47331e7-0.00326383
242AAPL2026-09-25T16:30:00336.04341.67334.53341.07341.073.00025e70.015331
243AAPL2026-09-28T16:30:00340.37342.99338.04338.4338.43.28208e7-0.00782834
244AAPL2026-09-29T16:30:00336.97337.09328.7329.4329.43.8478e7-0.0265957
245AAPL2026-09-30T16:30:00330.8339.5330.14333.02333.024.99886e70.0109897
246AAPL2026-10-01T16:30:00330.0332.48325.81330.32330.323.63063e7-0.00810757
247AAPL2026-10-02T16:30:00333.26334.54330.61333.69333.693.32786e70.0102022
248AAPL2026-10-05T16:30:00332.82336.21331.65332.89332.893.44009e7-0.0023974
249AAPL2026-10-06T16:30:00332.28334.38330.62333.63333.633.0449e70.00222293
250AAPL2026-10-07T16:30:00336.96338.67332.78336.67336.673.41479e70.00911192
251AAPL2026-10-08T16:30:00336.82341.57335.9340.42340.423.52799e70.0111385

Вычислим среднюю доходность за интервал стандартное отклонение доходности.

In [ ]:
доходности = skipmissing(df.Доходность)
println("Средняя интервальная доходность: ", round(mean(доходности) * 100, digits=3), "%")
println("Стандартное отклонение: ", round(std(доходности) * 100, digits=3), "%")
Средняя интервальная доходность: 0.129%
Стандартное отклонение: 1.557%

Построим график доходности.

In [ ]:
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])
Out[0]:

Построим гистограмму распределения доходностей за выбранные интервалы.

In [ ]:
histogram(
    collect(доходности) .* 100,
    bins = 40,
    xlabel = "Доходность, %",
    ylabel = "Количество",
    title = "$акция – распределение интервальных доходностей",
    label = false,
    fillcolor = RGB(0/255, 198/255, 201/255) )
Out[0]:

Волатильность

Определим период волатильности, указав количество интервалов.

In [ ]:
период_волатильности = 20
Out[0]:
20

Скользящая волатильность рассчитывается как стандартное отклонение доходностей в скользящем окне фиксированной длины. Построим график скользящей волатильности за выбранный период.

In [ ]:
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) )
Out[0]:

Накопленная доходность

Накопленная доходность рассчитывается как произведение множителей роста по всем интервалам:

где:

  • — порядковый номер интервала, для которого считается накопленная доходность.

  • — интервальная доходность на -м шаге.

    Построим график накопленной доходности.

In [ ]:
накопленная_доходность = 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 = "Начало")
Out[0]:

Просадка

Просадка показывает, насколько текущая цена ниже своего исторического максимума, достигнутого к данному моменту:

где:

  • — порядковый номер наблюдения;

  • — цена закрытия в момент t;

  • — исторический максимум цены за промежуток от начала периода до момента t включительно: , где — индекс, который перебирает все значения от до .

In [ ]:
цены = df.close
просадка = цены ./ accumulate(max, цены) .- 1
println("Максимальная просадка: ", round(minimum(просадка) * 100, digits=2), "%")
Максимальная просадка: -13.82%

Построим график просадки за выбранный период.

In [ ]:
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 = "")
Out[0]:

Итоговые характеристики акций

Отобразим итоговые характеристики акций выбранной компании.

In [ ]:
итог = 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(итог)
8×2 DataFrame
RowПоказательЗначение
StringFloat64
1Начальная цена254.04
2Конечная цена340.42
3Минимальная цена245.27
4Максимальная цена341.07
5Доходность за период34.0025
6Средняя интервальная доходность0.129267
7Волатильность доходности1.55665
8Максимальная просадка-13.823

Сравнение с другими акциями

Выполним извлечение котировок акций AAPL, MSFT, NVDA, AMZN; и построим график сравнения их накопленной доходности.

In [ ]:
акции = ["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. Построены графики динамики цены, объёма торгов, интервальной доходности, её распределения, скользящей волатильности, накопленной доходности и просадки. Рассчитаны итоговые характеристики, включая доходность за период, среднюю интервальную доходность, волатильность и максимальную просадку. Дополнительно выполнено сравнение накопленной доходности между акциями различных компаний.

Результаты работы имеют практическую ценность в различных областях, например:

  • в инвестиционном анализе – для оценки доходности и риска инструмента и его сравнения с аналогами;
  • в управлении портфелем – для контроля риска и принятия решений о приведении структуры инвестиционного портфеля к заданному целевому соотношению активов;
  • в исследованиях – подход легко переносится на другие акции, периоды и интервалы.

Полученные биржевые котировки могут являться исходными данными для более глубокого финансового анализа. Вы можете выбрать другие акции, периоды и интервалы для дальнейших исследований. Таким образом, набор методов, реализованный в данном примере, позволяет получить содержательные выводы о поведении финансового инструмента и служит удобной отправной точкой для более серьёзных исследований.