From 14127a4b916d1326335bf8c9e96873ca576e76d8 Mon Sep 17 00:00:00 2001 From: komarov Date: Fri, 24 Apr 2020 01:36:44 +0300 Subject: [PATCH] [WIP] arbitary chain storage & exchange provider --- .dockerignore | 3 + .gitignore | 3 +- docker-compose.override.yaml | 11 ++- docker-compose.yaml | 7 +- docker/php/Dockerfile | 15 ++- project/.env | 2 + project/composer.json | 1 + project/composer.lock | 70 ++++++++++++- project/config/services.yaml | 20 +++- .../{ => Inner}/ArbitrationChain.php | 0 .../Inner/ChainProviderInterface.php | 22 +++++ project/src/Command/TestCommand.php | 26 +++-- project/src/Exchanges/ExchangeInterface.php | 1 + project/src/Exchanges/ExchangeProvider.php | 33 +++++++ project/src/Exchanges/Kuna/KunaExchange.php | 17 +++- .../Arbitration/Inner/ChainProvider.php | 99 +++++++++++++++++++ .../src/Infrastucture/MongoClientFactory.php | 18 ++++ project/src/Utils/Money/CurrencyPair.php | 5 + project/symfony.lock | 3 + 19 files changed, 338 insertions(+), 18 deletions(-) create mode 100644 .dockerignore rename project/src/Arbitration/{ => Inner}/ArbitrationChain.php (100%) create mode 100644 project/src/Arbitration/Inner/ChainProviderInterface.php create mode 100644 project/src/Exchanges/ExchangeProvider.php create mode 100644 project/src/Infrastucture/Arbitration/Inner/ChainProvider.php create mode 100644 project/src/Infrastucture/MongoClientFactory.php diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7dd10ce --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +/.drone.yml +/docker +/docker-volumes \ No newline at end of file diff --git a/.gitignore b/.gitignore index 723ef36..d50adb6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.idea \ No newline at end of file +.idea +docker-volumes/ \ No newline at end of file diff --git a/docker-compose.override.yaml b/docker-compose.override.yaml index 434234b..4a37d2b 100644 --- a/docker-compose.override.yaml +++ b/docker-compose.override.yaml @@ -3,4 +3,13 @@ services: php: image: arbitry:local volumes: - - ./project:/srv/project + - ./project:/projects/main + + mongo: + command: "--wiredTigerCacheSizeGB 0.25" + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: q12asd3 + MONGO_INITDB_DATABASE: arbitry + volumes: + - ./docker-volumes/mongo:/data/db \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 631a0a3..35f6d70 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,4 +3,9 @@ services: php: environment: TZ: UTC - TERM: xterm \ No newline at end of file + TERM: xterm + mongo: + image: mongo + restart: unless-stopped + ports: + - 27017:27017 \ No newline at end of file diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index 33d8c83..8c274d4 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -7,10 +7,23 @@ ENV TERM xterm RUN apk add --update --no-cache \ libcurl \ bash \ -curl +curl \ +git \ +alpine-sdk \ +openssl-dev + +ENV EXT_MONGODB_VERSION=1.7.4 + +RUN docker-php-source extract \ + && git clone --branch $EXT_MONGODB_VERSION --depth 1 https://github.com/mongodb/mongo-php-driver.git /usr/src/php/ext/mongodb \ + && cd /usr/src/php/ext/mongodb && git submodule update --init \ + && docker-php-ext-install mongodb + RUN docker-php-ext-install bcmath COPY --from=composer /usr/bin/composer /usr/bin/composer COPY ./project /projects/main + +WORKDIR /projects/main diff --git a/project/.env b/project/.env index 2673d26..40198ed 100644 --- a/project/.env +++ b/project/.env @@ -19,3 +19,5 @@ APP_SECRET=2cb22b0116249ce29b70a2b0ab83a8e5 #TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 #TRUSTED_HOSTS='^(localhost|example\.com)$' ###< symfony/framework-bundle ### + +DATABASE_URL=mongodb://root:q12asd3@mongo:27017/?authenticationDatabase=admin \ No newline at end of file diff --git a/project/composer.json b/project/composer.json index d778c4f..7ddbb69 100644 --- a/project/composer.json +++ b/project/composer.json @@ -5,6 +5,7 @@ "php": "^7.2.5", "ext-ctype": "*", "ext-iconv": "*", + "mongodb/mongodb": "^1.6", "myclabs/php-enum": "^1.7", "nyholm/psr7": "^1.2", "psr/http-client": "^1.0", diff --git a/project/composer.lock b/project/composer.lock index cb83df0..0b9c80e 100644 --- a/project/composer.lock +++ b/project/composer.lock @@ -4,8 +4,76 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4e5589a47c5b0dc0e0cd3d924e0621aa", + "content-hash": "2ab113991ae6dde7f7448cf4e4e7f8d9", "packages": [ + { + "name": "mongodb/mongodb", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/mongodb/mongo-php-library.git", + "reference": "dc43ba25fb593d6a2988e6a535b6f5386eda5b15" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/dc43ba25fb593d6a2988e6a535b6f5386eda5b15", + "reference": "dc43ba25fb593d6a2988e6a535b6f5386eda5b15", + "shasum": "" + }, + "require": { + "ext-hash": "*", + "ext-json": "*", + "ext-mongodb": "^1.7", + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.27 || ^6.4 || ^8.3", + "sebastian/comparator": "^1.0 || ^2.0 || ^3.0", + "squizlabs/php_codesniffer": "^3.4", + "symfony/phpunit-bridge": "^4.4@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "MongoDB\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Andreas Braun", + "email": "andreas.braun@mongodb.com" + }, + { + "name": "Jeremy Mikola", + "email": "jmikola@gmail.com" + }, + { + "name": "Katherine Walker", + "email": "katherine.walker@mongodb.com" + } + ], + "description": "MongoDB driver library", + "homepage": "https://jira.mongodb.org/browse/PHPLIB", + "keywords": [ + "database", + "driver", + "mongodb", + "persistence" + ], + "time": "2020-02-04T18:16:35+00:00" + }, { "name": "myclabs/php-enum", "version": "1.7.6", diff --git a/project/config/services.yaml b/project/config/services.yaml index 81e9ad5..2bb66eb 100644 --- a/project/config/services.yaml +++ b/project/config/services.yaml @@ -11,6 +11,11 @@ services: autowire: true # Automatically injects dependencies in your services. autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. + _instanceof: + App\Exchanges\ExchangeInterface: + tags: + - { name: 'arbitry.exchange'} + # makes classes in src/ available to be used as services # this creates a service per class whose id is the fully-qualified class name App\: @@ -29,4 +34,17 @@ services: $privateKey: 'test' Http\Client\HttpClient: - class: Nyholm\HttpClient\Client \ No newline at end of file + class: Nyholm\HttpClient\Client + + MongoDB\Client: + factory: ['App\Infrastructure\MongoClientFactory', 'create'] + arguments: + - '%env(resolve:DATABASE_URL)%' + + App\Infrastructure\Arbitration\Inner\ChainProvider: ~ + + App\Arbitration\Inner\ChainProviderInterface: '@App\Infrastructure\Arbitration\Inner\ChainProvider' + + App\Exchanges\ExchangeProvider: + arguments: + - !tagged arbitry.exchange \ No newline at end of file diff --git a/project/src/Arbitration/ArbitrationChain.php b/project/src/Arbitration/Inner/ArbitrationChain.php similarity index 100% rename from project/src/Arbitration/ArbitrationChain.php rename to project/src/Arbitration/Inner/ArbitrationChain.php diff --git a/project/src/Arbitration/Inner/ChainProviderInterface.php b/project/src/Arbitration/Inner/ChainProviderInterface.php new file mode 100644 index 0000000..646392e --- /dev/null +++ b/project/src/Arbitration/Inner/ChainProviderInterface.php @@ -0,0 +1,22 @@ +kunaExchange = $kunaExchange; + $this->exchangeProvider = $exchangeProvider; + $this->chainProvider = $chainProvider; } public function execute(InputInterface $input, OutputInterface $output) { $finder = new ArbitrationMarketChainsFinder(); - $chains = $finder->findChainsInExchange($this->kunaExchange, 5); + $exchange = $this->exchangeProvider->getExchanges()[0]; + +// $chains = $finder->findChainsInExchange($exchange, 3); +// +// foreach ($chains as $chain) { +// $this->chainProvider->addChain($exchange, $chain); +// } - foreach ($chains as $chain) { + $fetchedChains = $this->chainProvider->getChainsForExchange($exchange); + foreach ($fetchedChains as $chain) { echo implode(' -> ', array_map( function (MarketInterface $market) { return $market->getPair()->getBase() . '/' . $market->getPair()->getQuote(); diff --git a/project/src/Exchanges/ExchangeInterface.php b/project/src/Exchanges/ExchangeInterface.php index 95fcc69..748f92c 100644 --- a/project/src/Exchanges/ExchangeInterface.php +++ b/project/src/Exchanges/ExchangeInterface.php @@ -9,6 +9,7 @@ namespace App\Exchanges; interface ExchangeInterface { + public function getName(): string; /** * @return MarketInterface[] */ diff --git a/project/src/Exchanges/ExchangeProvider.php b/project/src/Exchanges/ExchangeProvider.php new file mode 100644 index 0000000..9035ad5 --- /dev/null +++ b/project/src/Exchanges/ExchangeProvider.php @@ -0,0 +1,33 @@ +exchanges = $exchanges; + } + + /** + * @return ExchangeInterface[] + */ + public function getExchanges(): array + { + return iterator_to_array($this->exchanges->getIterator()); + } +} \ No newline at end of file diff --git a/project/src/Exchanges/Kuna/KunaExchange.php b/project/src/Exchanges/Kuna/KunaExchange.php index 4219c23..a2f7966 100644 --- a/project/src/Exchanges/Kuna/KunaExchange.php +++ b/project/src/Exchanges/Kuna/KunaExchange.php @@ -28,13 +28,22 @@ class KunaExchange implements ExchangeInterface */ public function getMarkets(): array { - $data = $this->apiExecutor->getMarkets(); + static $markets; - $markets = []; - foreach ($data as $marketData) { - $markets[] = KunaMarket::createFromApiData($marketData, $this->apiExecutor); + if (empty($markets)) { + $data = $this->apiExecutor->getMarkets(); + + $markets = []; + foreach ($data as $marketData) { + $markets[] = KunaMarket::createFromApiData($marketData, $this->apiExecutor); + } } return $markets; } + + public function getName(): string + { + return 'kuna'; + } } \ No newline at end of file diff --git a/project/src/Infrastucture/Arbitration/Inner/ChainProvider.php b/project/src/Infrastucture/Arbitration/Inner/ChainProvider.php new file mode 100644 index 0000000..d147d97 --- /dev/null +++ b/project/src/Infrastucture/Arbitration/Inner/ChainProvider.php @@ -0,0 +1,99 @@ +collection = $client->selectCollection('arbitry', 'inner_arbitration_chains'); + } + + /** + * @inheritDoc + */ + public function getChainsForExchange(ExchangeInterface $exchange): array + { + $rows = $this->collection->find(['exchange' => $exchange->getName()]); + + $markets = $exchange->getMarkets(); + + $chains = []; + foreach ($rows as $row) { + $chainMarkets = []; + foreach ($row['chain'] ?? [] as $chainData) { + foreach ($markets as $market) { + if ((string)$market->getPair() === $chainData) { + $chainMarkets[] = $market; + } + } + } + + if (!empty($chainMarkets)) { + $chains[] = new ArbitrationChain(...$chainMarkets); + } + } + + return $chains; + } + + protected function calculateChainHash(ExchangeInterface $exchange, ArbitrationChain $chain): string + { + return md5( + $exchange->getName() + . ';' + . implode( + ';', + array_map( + static function (MarketInterface $market): string + { + return (string)$market->getPair(); + }, + $chain->getMarkets() + ) + ) + ); + } + + public function addChain(ExchangeInterface $exchange, ArbitrationChain $chain): void + { + $this + ->collection + ->insertOne([ + '_id' => $this->calculateChainHash($exchange, $chain), + 'exchange' => $exchange->getName(), + 'chain' => array_map( + static function (MarketInterface $market): string + { + return (string)$market->getPair(); + }, + $chain->getMarkets() + ) + ]); + } + + public function removeChain(ExchangeInterface $exchange, ArbitrationChain $chain): void + { + $this + ->collection + ->deleteOne([ + '_id' => $this->calculateChainHash($exchange, $chain) + ]); + } +} \ No newline at end of file diff --git a/project/src/Infrastucture/MongoClientFactory.php b/project/src/Infrastucture/MongoClientFactory.php new file mode 100644 index 0000000..039c0b1 --- /dev/null +++ b/project/src/Infrastucture/MongoClientFactory.php @@ -0,0 +1,18 @@ +quote; } + + public function __toString() + { + return $this->base . '/' . $this->quote; + } } \ No newline at end of file diff --git a/project/symfony.lock b/project/symfony.lock index d7ea383..9e3e9f8 100644 --- a/project/symfony.lock +++ b/project/symfony.lock @@ -1,4 +1,7 @@ { + "mongodb/mongodb": { + "version": "1.6.0" + }, "myclabs/php-enum": { "version": "1.7.6" },