Professional Documents
Culture Documents
Іванник Записка
Іванник Записка
Дипломна робота
на здобуття ступеня бакалавра
Київ - 2023
2
ЗАТВЕРДЖУЮ
Завідувач кафедри
Наталія АУШЕВА
(підпис)
« » 2023р.
ЗАВДАННЯ
на дипломну роботу студенту
Іваннику Антону Олеговичу
(прізвище, ім’я, по батькові)
1. Тема роботи Прогнозування курсу кріптовалюти на основі лінійних
алгоритмів
КАЛЕНДАРНИЙ ПЛАН
АНОТАЦІЯ
ABSTRACT
This work aims to create a software system for forecasting the exchange
rate of cryptocurrency assets. The system is implemented using the PHP
programming language, the Laravel software framework, the Filament library for
admin panels, MySQL and PostgreSQL relational database management systems.
The result is a software product for analyzing and forecasting the course of
cryptocurrency assets.
Keywords: cryptocurrency, asset, forecasting, analysis.
The thesis was completed on 87 pages, contains 28 illustrations, 1 addition,
15 sources in the list of references.
6
ЗМІСТ
ПЕРЕЛІК УМОВНИХ ПОЗНАЧЕНЬ, СКОРОЧЕНЬ І ТЕРМІНІВ ..... 8
ВСТУП ...................................................................................................... 9
ВИСНОВКИ ............................................................................................ 63
ВСТУП
ринку.
Технічний аналіз базується на припущенні, що цінова динаміка має
певні закономірності та повторювані моделі. Він дозволяє інвесторам
виявити тренди, підтвердити їхню міцність, ідентифікувати ключові рівні
підтримки та опору та визначити потенційні точки входу та виходу з
позицій. Технічний аналіз використовує різноманітні технічні індикатори,
які надають інформацію про перекупленість або перепроданість активу та
допомагають виявляти зміни на ринку.
Лінійні алгоритми, такі як метод регресії найменших квадратів та
хребтова регресія, використовуються для аналізу та прогнозування
кріптовалютних даних на основі статистичних моделей. Вони дозволяють
побудувати математичні моделі, які описують залежність цінової динаміки
від різних факторів та також дозволяють інвесторам здійснювати прогнози
щодо майбутніх цінових рухів.
Застосування технічних та лінійних алгоритмів дозволяє інвесторам
отримувати обґрунтовані та об'єктивні рішення щодо управління своїми
кріптовалютними інвестиціями. Аналіз та прогнозування кріптовалютних
даних з використанням цих алгоритмів допомагають інвесторам визначати
оптимальні моменти для входу та виходу з позицій, зменшуючи ризики та
підвищуючи можливість отримання прибутку.
Метою дипломної роботи є створення програмного застосунку, який
використовує технічні та лінійні алгоритми для аналізу та прогнозування
кріптовалютних даних на основі японських свічок.
У зв’язку з цим були сформульовані наступні завдання:
1.2.1 Binance
1.2.2 Investing.com
1.2.3 CoinMarketCap
1.2.4 CoinGecko
1.2.5 CryptoCompare
2 ЛІНІЙНІ АЛГОРИТМИ
𝑆𝑀𝐴 = ∑ 𝑐𝑖
𝑖=0,..𝑛
3 ПРОГРАМНА РЕАЛІЗАЦІЯ
однієї таблиці.
Після запуску має пройти деякий час для того, щоб усі дані збереглися
у локальній базі даних сервісу адмін-панелі аналізатора. Після цього ми
можемо переглянути згенеровані дані на сторінці “Candlestick->Records”.
Приклад даних показаний на рисунку 4.6
57
ВИСНОВКИ
ДОДАТОК A
Текст програми
Аркушів 20
Київ - 2023
68
<?php
namespace App\Filament\Pages;
use
App\DataTransferObjects\Candlestick\CandlestickChartBar;
use App\Enums\AnalyticChartShouldBuyStatus;
use App\Enums\AssetRSIStatus;
use App\Enums\CandlestickIntervalTypeEnum;
use App\Models\AssetPair;
use App\Models\Candlestick;
use App\Services\Analysis\ML\LeastSquaresRegression;
use App\Services\Analysis\ML\RidgeRegression;
use
App\Services\Analysis\Technical\ExponentialMovingAverage;
use
App\Services\Analysis\Technical\RelativeStrengthIndex;
use App\Services\Analysis\Technical\SimpleMovingAverage;
use
App\Services\Analysis\Technical\StochasticRelativeStrengthInde
x;
use App\Services\Enum\EnumToKeyValueMapper;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Pages\Actions\Action;
use Filament\Pages\Page;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Str;
];
$this->candlesticks = Candlestick::query()
->where([
['asset_pair_id', $assetPair->id],
['interval_type',
self::DEFAULT_PERIOD_TYPE],
])
->limit(self::CANDLESTICKS_LIMIT)
71
->get()
->map(fn(Candlestick $candlestick) =>
CandlestickChartBar::fromCandlestick($candlestick,
self::DEFAULT_ASSET_PAIR));
}
$this->candlesticks = Candlestick::query()
72
->where([
['asset_pair_id',
$data['asset_pair_id']],
['interval_type',
CandlestickIntervalTypeEnum::tryFromName($data['interval_type'
])],
])
->whereDate('open_time', '>=',
$data['from_time'])
->whereDate('close_time', '<=',
$data['to_time'])
->limit(self::CANDLESTICKS_LIMIT)
->get()
->map(fn (Candlestick $candlestick) =>
CandlestickChartBar::fromCandlestick($candlestick,
$assetPairName));
$this->resetAnalyticsData();
$this-
>dispatchBrowserEvent('livewire:generate-candlestick-chart',
['candlesticks' => $this->candlesticks]);
})
->form([
Select::make('asset_pair_id')
->label('Asset Pair')
->options(AssetPair::all()-
>pluck('name', 'id')->toArray())
->required(),
Select::make('interval_type')
->label('Interval Type')
-
>options($enumToKeyValueMapper(CandlestickIntervalTypeEnum::cl
ass))
73
->required(),
DateTimePicker::make('from_time')
->maxDate(now())
->required(),
DateTimePicker::make('to_time')
->maxDate(now())
->required(),
]);
}
private function
getGenerateLeastSquaresRegressionChartAction(): Action
{
/** @var LeastSquaresRegression
$leastSquaresRegression */
$leastSquaresRegression =
App::make(LeastSquaresRegression::class);
$maxSamplesCount = $this->candlesticks->count() -
1;
$samples = $this->candlesticks-
>pluck($sampleFieldKey)
74
$trainSamples =
array_values(array_slice($samples, 0, $data['samples_count']));
$targets = $this->candlesticks-
>pluck($targetFieldKey)->take($data['samples_count'])-
>toArray();
$leastSquaresRegression-
>train($trainSamples, $targets);
$residualSamples =
array_values(array_slice($samples, -(count($samples) -
$data['samples_count'])));
$predictions = $leastSquaresRegression-
>predict($residualSamples);
$this->lSRSlopeCoefficients =
$leastSquaresRegression->getCoefficients();
$this-
>dispatchBrowserEvent('livewire:generate-least-squares-
regression-chart', [
'train_samples' => $trainSamples,
'prediction_samples' =>
$residualSamples,
'targets' => $targets,
'predictions' => $predictions,
'slope_coefficients' => $this-
>lSRSlopeCoefficients,
'intercept' =>
$leastSquaresRegression->getIntercept(),
]);
75
})
->form([
Select::make('sample_field_key')
->label('Regression sample field')
->options($this-
>candleBarRegressionSampleFieldNames)
->required(),
TextInput::make('samples_count')
->numeric()
->integer()
->minValue(1)
->maxValue($maxSamplesCount)
->hint('Max: '.$maxSamplesCount)
->required(),
]);
}
private function
getGenerateRidgeRegressionChartAction(): Action
{
/** @var RidgeRegression $ridgeRegression */
$ridgeRegression =
App::make(RidgeRegression::class);
$maxSamplesCount = $this->candlesticks->count() -
1;
]);
$targetFieldKey =
Str::camel(self::REGRESSION_TARGET_FIELD_NAME);
$samples = $this->candlesticks-
>pluck($sampleFieldKey)
->map(fn ($sample) => [$sample])
->toArray();
$trainSamples =
array_values(array_slice($samples, 0, $data['samples_count']));
$targets = $this->candlesticks-
>pluck($targetFieldKey)->take($data['samples_count'])-
>toArray();
$ridgeRegression->train($trainSamples,
$targets, $data['alpha']);
$residualSamples =
array_values(array_slice($samples, -(count($samples) -
$data['samples_count'])));
$predictions = $ridgeRegression-
>predict($residualSamples);
$this->ridgeRegressionSlopeCoefficients =
$ridgeRegression->getCoefficients();
$this-
>dispatchBrowserEvent('livewire:generate-ridge-regression-
chart', [
'train_samples' => $trainSamples,
'prediction_samples' =>
$residualSamples,
'targets' => $targets,
77
$this->lSRSlopeCoefficients = [];
$this->ridgeRegressionSlopeCoefficients = [];
}
$this->dispatchBrowserEvent('livewire:toggle-sma-
'.$period, ['sma_results' => $this->sMAResults[$period]]);
}
$sMAResults = $sMA->calculate($this-
>getCandlesticksClosePrices()->toArray(), $period);
return $this-
>mapTechIndicatorResultsWithTimestamps($sMAResults);
}
$this->dispatchBrowserEvent('livewire:toggle-ema-
'.$period, ['ema_results' => $this->eMAResults[$period]]);
}
$eMAResults = $eMA->calculate($this-
>getCandlesticksClosePrices()->toArray(), $period);
return $this-
>mapTechIndicatorResultsWithTimestamps($eMAResults);
}
? []
: $this->calculateRSI($period);
$this->dispatchBrowserEvent('livewire:toggle-rsi-
'.$period, ['rsi_results' => $this->rSIResults[$period]]);
}
$rSIResults = $rSI->calculate($this-
>getCandlesticksClosePrices()->toArray(), $period);
return $this-
>mapTechIndicatorResultsWithTimestamps($rSIResults);
}
$this->dispatchBrowserEvent('livewire:toggle-
stochastic-rsi-'.$period, ['rsi_results' => $this-
>stochasticRSIResults[$period]]);
}
{
/** @var StochasticRelativeStrengthIndex
$stochasticRSI */
$stochasticRSI =
App::make(StochasticRelativeStrengthIndex::class);
$rSIResults = $stochasticRSI->calculate($this-
>getCandlesticksClosePrices()->toArray(), $period);
return $this-
>mapTechIndicatorResultsWithTimestamps($rSIResults);
}
private function
mapTechIndicatorResultsWithTimestamps(array $sMAResults): array
{
$sMAResultsKeys = array_keys($sMAResults);
$resultsWithKeys = $this->candlesticks-
>filter(function (array $bar, int $key) use ($sMAResultsKeys) {
return in_array($key, $sMAResultsKeys, true);
})
->map(fn(array $bar, int $key) => [
'open_time_timestamp_ms' =>
$bar['openTimeTimestampMs'],
'result' => $sMAResults[$key],
])
->toArray();
return array_values($resultsWithKeys);
}
>shouldBuyOnStochasticRSI(3),
'assetStochasticRSI5Status' => $this-
>getAssetStochasticRSIStatus(5),
'shouldBuyOnStochasticRSI5' => $this-
>shouldBuyOnStochasticRSI(5),
'assetStochasticRSI7Status' => $this-
>getAssetStochasticRSIStatus(7),
'shouldBuyOnStochasticRSI7' => $this-
>shouldBuyOnStochasticRSI(7),
$lastIndex = count($this->sMAResults[$period]) -
1;
$lastValue = $this-
>sMAResults[$period][$lastIndex]['result'];
$penultimateValue = $this-
>sMAResults[$period][$lastIndex - 1]['result'];
$lastIndex = count($this->eMAResults[$period]) -
1;
$lastValue = $this-
>eMAResults[$period][$lastIndex]['result'];
$penultimateValue = $this-
>eMAResults[$period][$lastIndex - 1]['result'];
if (!$periodResults) {
return null;
}
$lastRSI = end($periodResults);
return AssetRSIStatus::Overbought;
}
return AssetRSIStatus::Oversold;
}
if (!$periodResults) {
return null;
}
86
$lastRSI = end($periodResults);
return AssetRSIStatus::Normal;
}
$coefficient = $this->lSRSlopeCoefficients[0];
$coefficient = $this-
>ridgeRegressionSlopeCoefficients[0];