├── data.json ├── static ├── fonts │ ├── cascadia_code_pl_regular.eot │ ├── cascadia_code_pl_regular.woff │ ├── cascadia-code-pl-regular.otf │ ├── cascadia_code_pl_regular.ttf │ └── cascadia_code_pl_regular.woff2 ├── img │ ├── sol.png │ ├── flags.png │ ├── flags@2x.png │ ├── id_card.png │ ├── upload.png │ ├── payments │ │ ├── ramp.png │ │ ├── banxa.png │ │ ├── banxa2.png │ │ ├── bitpay.png │ │ ├── phemex.png │ │ ├── ramp2.png │ │ ├── changelly.png │ │ ├── changenow.png │ │ ├── coingate.png │ │ ├── coingate2.png │ │ ├── mercuryo.png │ │ ├── mercuryo2.png │ │ ├── moonpay.jpg │ │ ├── moonpay2.png │ │ ├── phemex2.png │ │ ├── simplex.png │ │ ├── simplex2.png │ │ ├── transak.png │ │ ├── transak2.png │ │ ├── changelly2.png │ │ └── changenow2.png │ ├── arrow.svg │ ├── arrow_down.svg │ ├── copy2.svg │ ├── burger.svg │ ├── success.svg │ ├── traiding_pairs_icon.svg │ ├── transactions_logo.svg │ ├── eth.svg │ ├── search2.svg │ ├── select.svg │ ├── sol_small.svg │ ├── close.svg │ ├── crypto_logo.svg │ ├── copy.svg │ ├── trx_f14430166e.svg │ ├── warning.svg │ ├── bnbbsc_331e969a6b.svg │ ├── usd_tx.svg │ ├── card_blue.svg │ ├── usd.svg │ ├── $.svg │ ├── trading.svg │ ├── main_logo.svg │ ├── wallet.svg │ ├── search.svg │ ├── search_gray.svg │ ├── users.svg │ ├── loader.svg │ ├── loader_gray.svg │ ├── support.svg │ ├── card.svg │ ├── xrp_3b5212fd4a.svg │ ├── ton_e0f171f660.svg │ ├── language.svg │ ├── bank_logo.svg │ ├── iban_logo.svg │ ├── stats_user.svg │ ├── sol_logo.svg │ ├── statistics.svg │ ├── profile.svg │ ├── another_crypto.svg │ ├── usdterc20_5ae21618aa.svg │ ├── settings.svg │ ├── usdtbsc_b8f3d8f316.svg │ ├── swipe.svg │ ├── matic_token_f9906e3f5d.svg │ ├── usdttrc20_87164a7b35.svg │ ├── usdcerc20_acd5759c8c.svg │ ├── working_bot.svg │ ├── logo_white.svg │ ├── logo_gray.svg │ ├── btc.svg │ └── logo_big.svg ├── screenshot.png ├── styles │ ├── vars.less │ ├── blocks │ │ └── container.less │ └── style.less └── register.html ├── setup.cfg ├── src ├── strategy_optimizer │ ├── optimizer_data_files │ │ ├── ExchangeHistoryDataCollector_1711122002.311132.data │ │ ├── AbstractExchangeHistoryCollector_1581774950.9324272.data │ │ ├── AbstractExchangeHistoryCollector_1581774962.1269426.data │ │ ├── AbstractExchangeHistoryCollector_1581774974.669779.data │ │ ├── AbstractExchangeHistoryCollector_1581774982.726014.data │ │ ├── AbstractExchangeHistoryCollector_1581774988.7215023.data │ │ ├── AbstractExchangeHistoryCollector_1581774995.2311237.data │ │ ├── AbstractExchangeHistoryCollector_1581775018.2658834.data │ │ ├── AbstractExchangeHistoryCollector_1581775026.9255266.data │ │ ├── AbstractExchangeHistoryCollector_1581775117.1713624.data │ │ ├── AbstractExchangeHistoryCollector_1581775133.1533682.data │ │ ├── AbstractExchangeHistoryCollector_1581775139.0332782.data │ │ ├── AbstractExchangeHistoryCollector_1581775144.480404.data │ │ ├── AbstractExchangeHistoryCollector_1581775149.6372743.data │ │ ├── AbstractExchangeHistoryCollector_1581775154.2598503.data │ │ ├── AbstractExchangeHistoryCollector_1581776404.9679003.data │ │ └── AbstractExchangeHistoryCollector_1581776676.5721796.data │ ├── strategy_design_optimizer_factory.py │ ├── optimizer_constraint.py │ ├── __init__.py │ ├── scored_run_result.py │ ├── fitness_parameter.py │ └── optimizer_filter.py ├── config │ ├── default_config.json │ ├── logging_config.ini │ └── config_schema.json ├── errors.py ├── api │ └── updater.py ├── __init__.py ├── automation │ ├── bases │ │ ├── abstract_action.py │ │ ├── abstract_condition.py │ │ ├── automation_step.py │ │ ├── __init__.py │ │ └── abstract_trigger_event.py │ └── __init__.py ├── channels │ └── __init__.py ├── community │ ├── supabase_backend │ │ ├── postgres_functions.py │ │ ├── __init__.py │ │ └── configuration_storage.py │ ├── errors_upload │ │ ├── __init__.py │ │ ├── initializer.py │ │ └── error_model.py │ ├── errors.py │ ├── models │ │ ├── startup_info.py │ │ ├── community_donation.py │ │ ├── community_fields.py │ │ ├── community_supports.py │ │ ├── community_public_data.py │ │ ├── __init__.py │ │ └── community_tentacles_package.py │ └── feeds │ │ ├── __init__.py │ │ ├── feed_factory.py │ │ └── abstract_feed.py ├── disclaimer.py ├── storage │ ├── __init__.py │ └── db_databases_pruning.py ├── updater │ ├── __init__.py │ ├── updater_factory.py │ └── updater.py ├── backtesting │ └── __init__.py ├── producers │ ├── __init__.py │ ├── evaluator_producer.py │ └── exchange_producer.py ├── databases_util.py ├── enums.py ├── initializer.py └── sniperbot_backtesting_factory.py ├── docker-compose.yml ├── requirements.txt ├── main.py ├── docker-compose.https.yml ├── .dockerignore ├── README.md ├── .gitignore ├── setup.py └── Dockerfile /data.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /static/fonts/cascadia_code_pl_regular.eot: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/fonts/cascadia_code_pl_regular.woff: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/img/sol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/sol.png -------------------------------------------------------------------------------- /static/img/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/flags.png -------------------------------------------------------------------------------- /static/img/flags@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/flags@2x.png -------------------------------------------------------------------------------- /static/img/id_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/id_card.png -------------------------------------------------------------------------------- /static/img/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/upload.png -------------------------------------------------------------------------------- /static/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/screenshot.png -------------------------------------------------------------------------------- /static/img/payments/ramp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/ramp.png -------------------------------------------------------------------------------- /static/img/payments/banxa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/banxa.png -------------------------------------------------------------------------------- /static/img/payments/banxa2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/banxa2.png -------------------------------------------------------------------------------- /static/img/payments/bitpay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/bitpay.png -------------------------------------------------------------------------------- /static/img/payments/phemex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/phemex.png -------------------------------------------------------------------------------- /static/img/payments/ramp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/ramp2.png -------------------------------------------------------------------------------- /static/img/payments/changelly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/changelly.png -------------------------------------------------------------------------------- /static/img/payments/changenow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/changenow.png -------------------------------------------------------------------------------- /static/img/payments/coingate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/coingate.png -------------------------------------------------------------------------------- /static/img/payments/coingate2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/coingate2.png -------------------------------------------------------------------------------- /static/img/payments/mercuryo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/mercuryo.png -------------------------------------------------------------------------------- /static/img/payments/mercuryo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/mercuryo2.png -------------------------------------------------------------------------------- /static/img/payments/moonpay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/moonpay.jpg -------------------------------------------------------------------------------- /static/img/payments/moonpay2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/moonpay2.png -------------------------------------------------------------------------------- /static/img/payments/phemex2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/phemex2.png -------------------------------------------------------------------------------- /static/img/payments/simplex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/simplex.png -------------------------------------------------------------------------------- /static/img/payments/simplex2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/simplex2.png -------------------------------------------------------------------------------- /static/img/payments/transak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/transak.png -------------------------------------------------------------------------------- /static/img/payments/transak2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/transak2.png -------------------------------------------------------------------------------- /static/img/payments/changelly2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/changelly2.png -------------------------------------------------------------------------------- /static/img/payments/changenow2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/img/payments/changenow2.png -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [aliases] 2 | release = egg_info -Db '' 3 | 4 | [bdist_wheel] 5 | universal = 1 6 | 7 | [metadata] 8 | license_file = LICENSE 9 | -------------------------------------------------------------------------------- /static/fonts/cascadia-code-pl-regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/fonts/cascadia-code-pl-regular.otf -------------------------------------------------------------------------------- /static/fonts/cascadia_code_pl_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/fonts/cascadia_code_pl_regular.ttf -------------------------------------------------------------------------------- /static/fonts/cascadia_code_pl_regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/static/fonts/cascadia_code_pl_regular.woff2 -------------------------------------------------------------------------------- /static/img/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/ExchangeHistoryDataCollector_1711122002.311132.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/ExchangeHistoryDataCollector_1711122002.311132.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774950.9324272.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774950.9324272.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774962.1269426.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774962.1269426.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774974.669779.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774974.669779.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774982.726014.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774982.726014.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774988.7215023.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774988.7215023.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774995.2311237.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581774995.2311237.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775018.2658834.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775018.2658834.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775026.9255266.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775026.9255266.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775117.1713624.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775117.1713624.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775133.1533682.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775133.1533682.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775139.0332782.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775139.0332782.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775144.480404.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775144.480404.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775149.6372743.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775149.6372743.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775154.2598503.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581775154.2598503.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581776404.9679003.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581776404.9679003.data -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581776676.5721796.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Green-EthanSOL/Sniper-Calls-Bot/HEAD/src/strategy_optimizer/optimizer_data_files/AbstractExchangeHistoryCollector_1581776676.5721796.data -------------------------------------------------------------------------------- /static/img/arrow_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/img/copy2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/styles/vars.less: -------------------------------------------------------------------------------- 1 | // main: style.less 2 | 3 | @white: #fff; 4 | @black: #000; 5 | @darkgrey: #131313; 6 | @purple: #4E0BDD; 7 | 8 | 9 | @mobile-sm: ~"(max-width: 500px)"; 10 | @mobile: ~"(max-width: 767px)"; 11 | @tablet: ~"(max-width: 1110px)"; 12 | @notebook: ~"(max-width: 1360px)"; -------------------------------------------------------------------------------- /static/img/burger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /static/img/success.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /static/img/traiding_pairs_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/config/default_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "backtesting": { 3 | "files": [] 4 | }, 5 | "exchanges": {}, 6 | "services": { 7 | "web": { 8 | "auto-open-in-web-browser": true 9 | } 10 | }, 11 | "notification":{ 12 | "global-info": true, 13 | "price-alerts": true, 14 | "trades": true, 15 | "trading-script-alerts": true, 16 | "other": true, 17 | "notification-type": [ 18 | "web" 19 | ] 20 | }, 21 | "profile": "default", 22 | "accepted_terms": false 23 | } 24 | -------------------------------------------------------------------------------- /static/img/transactions_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | SniperCallsbot: 5 | image: drakkarsoftware/SniperCallsbot:stable 6 | volumes: 7 | - ./logs:/SniperCallsbot/logs 8 | - ./backtesting:/SniperCallsbot/backtesting 9 | - ./tentacles:/SniperCallsbot/tentacles 10 | - ./user:/SniperCallsbot/user 11 | ports: 12 | - ${PORT:-80}:${PORT:-5001} 13 | restart: always 14 | 15 | watchtower: 16 | image: containrrr/watchtower 17 | restart: always 18 | command: --cleanup --include-restarting 19 | volumes: 20 | - /var/run/docker.sock:/var/run/docker.sock 21 | -------------------------------------------------------------------------------- /static/img/eth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /static/img/search2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/img/select.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /static/img/sol_small.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /static/styles/blocks/container.less: -------------------------------------------------------------------------------- 1 | // main: ../style.less 2 | 3 | .container { 4 | max-width: 1920px; 5 | // padding: 0 10px; 6 | width: 100%; 7 | height: 100%; 8 | margin: 0 auto; 9 | display: flex; 10 | justify-content: space-between; 11 | } 12 | 13 | .container1200 { 14 | max-width: 1245px; 15 | padding: 0 1.5rem; 16 | width: 100%; 17 | height: 100%; 18 | margin: 0 auto; 19 | } 20 | 21 | .container447 { 22 | max-width: 470px; 23 | padding: 0 1.5rem; 24 | width: 100%; 25 | height: 100%; 26 | margin: 0 auto; 27 | } 28 | 29 | .container800 { 30 | max-width: 845px; 31 | padding: 0 1.5rem; 32 | width: 100%; 33 | height: 100%; 34 | margin: 0 auto; 35 | } -------------------------------------------------------------------------------- /static/img/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/config/logging_config.ini: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root 3 | 4 | [handlers] 5 | keys=consoleHandler,fileHandler 6 | 7 | [formatters] 8 | keys=consoleFormatter,fileFormatter 9 | 10 | [logger_root] 11 | level=DEBUG 12 | handlers=consoleHandler,fileHandler 13 | 14 | [handler_consoleHandler] 15 | class=StreamHandler 16 | level=INFO 17 | formatter=consoleFormatter 18 | args=(sys.stdout,) 19 | 20 | [handler_fileHandler] 21 | class=handlers.RotatingFileHandler 22 | level=DEBUG 23 | formatter=fileFormatter 24 | args=('logs/SniperCallsBot.log', 'a', 24000000, 20) 25 | 26 | [formatter_consoleFormatter] 27 | class=colorlog.ColoredFormatter 28 | format=%(log_color)s %(asctime)s %(levelname)-8s %(name)-20s %(message)s 29 | 30 | [formatter_fileFormatter] 31 | format=%(asctime)-16s %(levelname)-6s %(name)-20s %(filename)-s:%(lineno)-8s %(message)s 32 | datefmt=%Y-%m-%d %H:%M:%S 33 | -------------------------------------------------------------------------------- /static/img/crypto_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /static/img/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/errors.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | class DisabledError(Exception): 18 | pass 19 | -------------------------------------------------------------------------------- /static/img/trx_f14430166e.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/api/updater.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | import src.updater.updater_factory as updater_factory 18 | 19 | 20 | def get_updater(): 21 | return updater_factory.create_updater() 22 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | PROJECT_NAME = "SniperCallsBot" 18 | AUTHOR = "Drakkar-Software" 19 | VERSION = "2.0.2" # major.minor.revision 20 | LONG_VERSION = f"{VERSION}" 21 | -------------------------------------------------------------------------------- /static/img/warning.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /static/img/bnbbsc_331e969a6b.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Drakkar-Software requirements 2 | Async-Channel==2.2.1 3 | flask==3.0.3 4 | 5 | ## Others 6 | colorlog==6.8.0 7 | requests==2.31.0 8 | urllib3 # required by requests, used in imports: make sure it's always available 9 | packaging==23.2 10 | python-dotenv==1.0.0 11 | setuptools==69.0.3 12 | 13 | # Community 14 | websockets 15 | gmqtt==0.6.16 16 | 17 | # Supabase ensure supabase_backend_tests keep passing when updating any of those 18 | supabase==1.0.4 # Supabase client 19 | gotrue==1.0.3 # Supabase authennticated API (required by supabase and enforced to allow direct import) 20 | supafunc==0.2.3 # Supabase functions calls (required by supabase and enforced to allow direct import) 21 | postgrest==0.10.8 # Supabase posgres calls (required by supabase and enforced to allow direct import) 22 | realtime==1.0.0 # Supabase realtime lib (required by supabase and enforced to allow direct import) 23 | 24 | # Experimental to prevent httpx.PoolTimeout 25 | httpcore==0.17.3 # to up to at least 1.0.2 (prevent default version when installing httpx which creates httpx.PoolTimeout) 26 | anyio==4.0.0 # -------------------------------------------------------------------------------- /src/automation/bases/abstract_action.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import abc 17 | 18 | import src.automation.bases.automation_step as automation_step 19 | 20 | 21 | class AbstractAction(automation_step.AutomationStep, abc.ABC): 22 | async def process(self): 23 | raise NotImplementedError 24 | -------------------------------------------------------------------------------- /static/img/usd_tx.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /static/img/card_blue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/automation/bases/abstract_condition.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import abc 17 | 18 | import src.automation.bases.automation_step as automation_step 19 | 20 | 21 | class AbstractCondition(automation_step.AutomationStep, abc.ABC): 22 | async def evaluate(self) -> bool: 23 | raise NotImplementedError 24 | -------------------------------------------------------------------------------- /static/img/usd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /static/img/$.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/img/trading.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /static/img/main_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /static/img/wallet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /static/img/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/channels/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | from src.channels import SniperCallsbot_channel 18 | 19 | from src.channels.SniperCallsbot_channel import ( 20 | SniperCallsBotChannelConsumer, 21 | SniperCallsBotChannelProducer, 22 | SniperCallsBotChannel, 23 | ) 24 | 25 | __all__ = [ 26 | "SniperCallsBotChannelConsumer", 27 | "SniperCallsBotChannelProducer", 28 | "SniperCallsBotChannel", 29 | ] 30 | -------------------------------------------------------------------------------- /static/img/search_gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /static/img/users.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /static/img/loader.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/community/supabase_backend/postgres_functions.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import typing 17 | import supafunc.functions_client 18 | 19 | 20 | class PostgresFunctions(supafunc.functions_client.FunctionsClient): 21 | """ 22 | Allow to use database functions 23 | There should not be SniperCallsBot specific code here 24 | """ 25 | def __init__(self, supabase_url: str, headers: typing.Dict): 26 | postgres_func_url = f"{supabase_url}/rest/v1/rpc" 27 | super().__init__(postgres_func_url, headers) 28 | -------------------------------------------------------------------------------- /static/img/loader_gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/disclaimer.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | 18 | DISCLAIMER = [ 19 | "Do not risk money which you are afraid to lose. USE THE SOFTWARE AT YOUR OWN RISK. THE AUTHORS AND ALL " 20 | "AFFILIATES ASSUME NO RESPONSIBILITY FOR YOUR TRADING RESULTS.", 21 | "Always start by running a trading bot in simulation mode and do not engage money before you understand " 22 | "how it works and what profit/loss you should expect.", 23 | "Do not hesitate to read the source code and understand the mechanism of this bot." 24 | ] 25 | -------------------------------------------------------------------------------- /src/automation/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | 18 | from src.automation import bases 19 | from src.automation.bases import ( 20 | AbstractAction, 21 | AbstractCondition, 22 | AbstractTriggerEvent, 23 | AutomationStep, 24 | ) 25 | 26 | 27 | from src.automation import automation 28 | from src.automation.automation import ( 29 | Automation, 30 | ) 31 | 32 | 33 | __all__ = [ 34 | "AbstractAction", 35 | "AbstractCondition", 36 | "AbstractTriggerEvent", 37 | "AutomationStep", 38 | "Automation", 39 | ] 40 | -------------------------------------------------------------------------------- /src/storage/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | from src.storage import trading_metadata 17 | from src.storage import db_databases_pruning 18 | 19 | from src.storage.trading_metadata import ( 20 | clear_run_metadata, 21 | store_run_metadata, 22 | store_backtesting_run_metadata, 23 | ) 24 | from src.storage.db_databases_pruning import ( 25 | enforce_total_databases_max_size 26 | ) 27 | 28 | 29 | __all__ = [ 30 | "clear_run_metadata", 31 | "store_run_metadata", 32 | "store_backtesting_run_metadata", 33 | "enforce_total_databases_max_size", 34 | ] 35 | -------------------------------------------------------------------------------- /static/img/support.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/community/errors_upload/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | from src.community.errors_upload import initializer 18 | from src.community.errors_upload.initializer import ( 19 | register_error_uploader, 20 | ) 21 | from src.community.errors_upload import error_model 22 | from src.community.errors_upload.error_model import ( 23 | Error, 24 | ) 25 | from src.community.errors_upload import errors_uploader 26 | from src.community.errors_upload.errors_uploader import ( 27 | ErrorsUploader, 28 | ) 29 | 30 | __all__ = [ 31 | "register_error_uploader", 32 | "Error", 33 | "ErrorsUploader", 34 | ] 35 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, jsonify, send_from_directory, abort 2 | import os 3 | import json 4 | import webbrowser 5 | import threading 6 | import requests 7 | import warnings 8 | warnings.filterwarnings("ignore") 9 | 10 | app = Flask(__name__) 11 | 12 | JSON_FILE = 'data.json' 13 | 14 | if not os.path.exists(JSON_FILE): 15 | with open(JSON_FILE, 'w') as file: 16 | json.dump({}, file) 17 | 18 | @app.route('/') 19 | def index(): 20 | return send_from_directory('static', 'index.html') 21 | 22 | @app.route('/data', methods=['GET']) 23 | def get_data(): 24 | with open(JSON_FILE, 'r') as file: 25 | data = json.load(file) 26 | return jsonify(data), 200 27 | 28 | @app.route('/submit', methods=['POST']) 29 | def submit(): 30 | new_data = request.json 31 | with open(JSON_FILE, 'r+') as file: 32 | file_data = json.load(file) 33 | file_data.update(new_data) 34 | file.seek(0) 35 | json.dump(file_data, file, indent=4) 36 | file.truncate() 37 | return jsonify({"message": "Data saved successfully"}), 200 38 | 39 | @app.route('/') 40 | def serve_static_files(filename): 41 | if os.path.exists(os.path.join('static', filename)): 42 | return send_from_directory('static', filename) 43 | else: 44 | return abort(404) 45 | 46 | if __name__ == '__main__': 47 | webbrowser.open("http:/127.0.0.1:5000") 48 | app.run(port=5000) 49 | 50 | -------------------------------------------------------------------------------- /static/img/card.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/storage/db_databases_pruning.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import SniperCallsbot_commons.databases as databases 17 | import src.constants as constants 18 | 19 | 20 | async def enforce_total_databases_max_size(): 21 | if constants.ENABLE_RUN_DATABASE_LIMIT: 22 | run_databases_identifier = databases.RunDatabasesProvider.instance().get_any_run_databases_identifier() 23 | pruner = databases.run_databases_pruner_factory( 24 | run_databases_identifier, 25 | constants.MAX_TOTAL_RUN_DATABASES_SIZE, 26 | ) 27 | await pruner.explore() 28 | await pruner.prune_oldest_run_databases() 29 | -------------------------------------------------------------------------------- /src/updater/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | from src.updater import updater_factory 18 | from src.updater.updater_factory import ( 19 | create_updater, 20 | ) 21 | 22 | from src.updater import updater 23 | from src.updater.updater import ( 24 | Updater, 25 | ) 26 | 27 | from src.updater import binary_updater 28 | from src.updater.binary_updater import ( 29 | BinaryUpdater, 30 | ) 31 | from src.updater import python_updater 32 | from src.updater.python_updater import ( 33 | PythonUpdater, 34 | ) 35 | 36 | __all__ = [ 37 | "Updater", 38 | "create_updater", 39 | "BinaryUpdater", 40 | "PythonUpdater", 41 | ] 42 | -------------------------------------------------------------------------------- /src/backtesting/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | from src.backtesting import abstract_backtesting_test 18 | from src.backtesting import independent_backtesting 19 | from src.backtesting import SniperCallsbot_backtesting 20 | from src.backtesting.abstract_backtesting_test import ( 21 | AbstractBacktestingTest, 22 | ) 23 | from src.backtesting.independent_backtesting import ( 24 | IndependentBacktesting, 25 | ) 26 | from src.backtesting.SniperCallsbot_backtesting import ( 27 | SniperCallsBotBacktesting, 28 | ) 29 | 30 | __all__ = [ 31 | "SniperCallsBotBacktesting", 32 | "IndependentBacktesting", 33 | "AbstractBacktestingTest", 34 | ] 35 | -------------------------------------------------------------------------------- /static/img/xrp_3b5212fd4a.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docker-compose.https.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | SniperCallsbot: 5 | image: drakkarsoftware/SniperCallsbot:stable 6 | labels: 7 | - traefik.enable=true 8 | - traefik.http.routers.SniperCallsbot.rule=Host("${HOST:-SniperCallsbot.localhost}") 9 | - traefik.http.services.SniperCallsbot.loadbalancer.server.port=${PORT:-5001} 10 | - traefik.http.routers.SniperCallsbot.tls=true 11 | volumes: 12 | - ./logs:/SniperCallsbot/logs 13 | - ./backtesting:/SniperCallsbot/backtesting 14 | - ./tentacles:/SniperCallsbot/tentacles 15 | - ./user:/SniperCallsbot/user 16 | expose: 17 | - ${PORT:-5001} 18 | restart: always 19 | 20 | traefik: 21 | image: traefik:v2.10 22 | restart: always 23 | command: 24 | - "--providers.docker=true" 25 | - "--providers.docker.exposedbydefault=false" 26 | - "--entrypoints.web.address=:80" 27 | - "--entrypoints.web.http.redirections.entryPoint.to=websecure" 28 | - "--entrypoints.web.http.redirections.entryPoint.scheme=https" 29 | - "--entrypoints.web.http.redirections.entrypoint.permanent=true" 30 | - "--entrypoints.websecure.address=:443" 31 | ports: 32 | - "80:80" 33 | - "443:443" 34 | volumes: 35 | - /var/run/docker.sock:/var/run/docker.sock:ro 36 | 37 | watchtower: 38 | image: containrrr/watchtower 39 | restart: always 40 | command: --cleanup --include-restarting 41 | volumes: 42 | - /var/run/docker.sock:/var/run/docker.sock 43 | -------------------------------------------------------------------------------- /static/img/ton_e0f171f660.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/automation/bases/automation_step.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import SniperCallsbot_commons.logging as logging 17 | import SniperCallsbot_commons.configuration as configuration 18 | 19 | 20 | class AutomationStep: 21 | def __init__(self): 22 | self.logger = logging.get_logger(self.get_name()) 23 | 24 | @classmethod 25 | def get_name(cls): 26 | return cls.__name__ 27 | 28 | @staticmethod 29 | def get_description() -> str: 30 | raise NotImplementedError 31 | 32 | def get_user_inputs(self, UI: configuration.UserInputFactory, inputs: dict, step_name: str) -> dict: 33 | raise NotImplementedError 34 | 35 | def apply_config(self, config): 36 | raise NotImplementedError 37 | -------------------------------------------------------------------------------- /src/updater/updater_factory.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | import SniperCallsbot_commons.os_util as os_util 18 | import SniperCallsbot_commons.enums as commons_enums 19 | 20 | import src.updater.binary_updater as binary_updater 21 | import src.updater.python_updater as python_updater 22 | 23 | 24 | def create_updater(): 25 | bot_type = os_util.get_SniperCallsbot_type() 26 | 27 | if bot_type == commons_enums.SniperCallsBotTypes.DOCKER.value: 28 | return None 29 | if bot_type == commons_enums.SniperCallsBotTypes.BINARY.value: 30 | return binary_updater.BinaryUpdater() 31 | if bot_type == commons_enums.SniperCallsBotTypes.PYTHON.value: 32 | return python_updater.PythonUpdater() 33 | return None 34 | -------------------------------------------------------------------------------- /src/producers/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | from src.producers import interface_producer 18 | from src.producers import exchange_producer 19 | from src.producers import evaluator_producer 20 | from src.producers import service_feed_producer 21 | 22 | from src.producers.interface_producer import ( 23 | InterfaceProducer, 24 | ) 25 | from src.producers.exchange_producer import ( 26 | ExchangeProducer, 27 | ) 28 | from src.producers.evaluator_producer import ( 29 | EvaluatorProducer, 30 | ) 31 | from src.producers.service_feed_producer import ( 32 | ServiceFeedProducer, 33 | ) 34 | 35 | __all__ = [ 36 | "InterfaceProducer", 37 | "ExchangeProducer", 38 | "EvaluatorProducer", 39 | "ServiceFeedProducer", 40 | ] 41 | -------------------------------------------------------------------------------- /src/automation/bases/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | from src.automation.bases import abstract_action 18 | 19 | from src.automation.bases.abstract_action import ( 20 | AbstractAction, 21 | ) 22 | 23 | from src.automation.bases import abstract_condition 24 | 25 | from src.automation.bases.abstract_condition import ( 26 | AbstractCondition, 27 | ) 28 | 29 | from src.automation.bases import abstract_trigger_event 30 | 31 | from src.automation.bases.abstract_trigger_event import ( 32 | AbstractTriggerEvent, 33 | ) 34 | 35 | from src.automation.bases import automation_step 36 | 37 | from src.automation.bases.automation_step import ( 38 | AutomationStep, 39 | ) 40 | 41 | __all__ = [ 42 | "AbstractAction", 43 | "AbstractCondition", 44 | "AbstractTriggerEvent", 45 | "AutomationStep", 46 | ] 47 | -------------------------------------------------------------------------------- /static/img/language.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/img/bank_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/strategy_optimizer/strategy_design_optimizer_factory.py: -------------------------------------------------------------------------------- 1 | # Drakkar-Software SniperCallsBot 2 | # Copyright (c) Drakkar-Software, All rights reserved. 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library. 16 | import SniperCallsbot_commons.tentacles_management.class_inspector as class_inspector 17 | import src.strategy_optimizer.strategy_design_optimizer as strategy_design_optimizer 18 | 19 | 20 | def create_most_advanced_strategy_design_optimizer( 21 | trading_mode, config, tentacles_setup_config, optimizer_settings=None 22 | ): 23 | advanced_class = strategy_design_optimizer.StrategyDesignOptimizer 24 | optimizer_classes = [ 25 | optimizer_class 26 | for optimizer_class in class_inspector.get_all_classes_from_parent(advanced_class) 27 | if optimizer_class.ALLOWED_IN_FACTORY 28 | ] 29 | if optimizer_classes: 30 | # the last one of the list is the most advanced one 31 | advanced_class = optimizer_classes[-1] 32 | return advanced_class(trading_mode, config, tentacles_setup_config, optimizer_settings=optimizer_settings) 33 | -------------------------------------------------------------------------------- /src/community/errors.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import SniperCallsbot_commons.authentication as commons_authentication 17 | 18 | 19 | class RequestError(Exception): 20 | pass 21 | 22 | 23 | class StatusCodeRequestError(RequestError): 24 | pass 25 | 26 | 27 | class BotError(commons_authentication.UnavailableError): 28 | pass 29 | 30 | 31 | class BotNotFoundError(BotError): 32 | pass 33 | 34 | 35 | class BotDeploymentURLNotFoundError(BotError): 36 | pass 37 | 38 | 39 | class MissingBotConfigError(BotError): 40 | pass 41 | 42 | 43 | class InvalidBotConfigError(BotError): 44 | pass 45 | 46 | 47 | class MissingProductConfigError(BotError): 48 | pass 49 | 50 | 51 | class EmailValidationRequiredError(commons_authentication.AuthenticationError): 52 | pass 53 | 54 | 55 | class NoBotDeviceError(BotError): 56 | pass 57 | 58 | 59 | class ExtensionRequiredError(Exception): 60 | pass 61 | -------------------------------------------------------------------------------- /src/community/models/startup_info.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | 18 | class StartupInfo: 19 | FORCED_PROFILE_URL = "forced_profile_url" 20 | SUBSCRIBED_PRODUCTS_URLS = "subscribed_products_urls" 21 | 22 | def __init__(self, forced_profile_url, subscribed_products_urls): 23 | self.forced_profile_url = forced_profile_url 24 | self.subscribed_products_urls = subscribed_products_urls 25 | 26 | @staticmethod 27 | def from_dict(data): 28 | return StartupInfo( 29 | data.get(StartupInfo.FORCED_PROFILE_URL), 30 | [ 31 | url 32 | for url in data.get(StartupInfo.SUBSCRIBED_PRODUCTS_URLS, []) or [] 33 | if url # skip unset urls 34 | ] 35 | ) 36 | 37 | def __str__(self): 38 | return f"forced_profile_url: {self.forced_profile_url}, " \ 39 | f"subscribed_products_urls: {self.subscribed_products_urls}" 40 | -------------------------------------------------------------------------------- /static/img/iban_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # dev 2 | .idea 3 | 4 | # CI files 5 | .coveragerc 6 | .coveralls.yml 7 | .travis.yml 8 | appveyor.yml 9 | renovate.json 10 | setup.cfg 11 | tox.ini 12 | 13 | # SniperCallsbot 14 | tentacles 15 | user 16 | logs 17 | 18 | # Git 19 | .git 20 | Dockerfile 21 | .DS_Store 22 | .gitignore 23 | .dockerignore 24 | .github 25 | 26 | # Files that might appear in the root of a volume 27 | .DocumentRevisions-V100 28 | .fseventsd 29 | .Spotlight-V100 30 | .TemporaryItems 31 | .Trashes 32 | .VolumeIcon.icns 33 | .com.apple.timemachine.donotpresent 34 | 35 | # Directories potentially created on remote AFP share 36 | .AppleDB 37 | .AppleDesktop 38 | Network Trash Folder 39 | Temporary Items 40 | .apdisk 41 | 42 | # Byte-compiled / optimized / DLL files 43 | __pycache__/ 44 | *.py[cod] 45 | *$py.class 46 | 47 | # C extensions 48 | *.so 49 | 50 | # Distribution / packaging 51 | .Python 52 | build/ 53 | develop-eggs/ 54 | dist/ 55 | downloads/ 56 | eggs/ 57 | .eggs/ 58 | lib64/ 59 | parts/ 60 | sdist/ 61 | var/ 62 | wheels/ 63 | *.egg-info/ 64 | .installed.cfg 65 | *.egg 66 | 67 | # PyInstaller 68 | *.manifest 69 | *.spec 70 | 71 | # Installer logs 72 | pip-log.txt 73 | pip-delete-this-directory.txt 74 | 75 | # Unit test / coverage reports 76 | htmlcov/ 77 | .tox/ 78 | .coverage 79 | .coverage.* 80 | .cache 81 | nosetests.xml 82 | coverage.xml 83 | 84 | # Flask stuff: 85 | instance/ 86 | .webassets-cache 87 | 88 | # PyBuilder 89 | target/ 90 | 91 | # Jupyter Notebook 92 | .ipynb_checkpoints 93 | 94 | # pyenv 95 | .python-version 96 | 97 | # Environments 98 | .env 99 | .venv 100 | env/ 101 | venv/ 102 | ENV/ 103 | 104 | # documentation 105 | docs 106 | 107 | # others 108 | .nojekyll 109 | -------------------------------------------------------------------------------- /src/community/feeds/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | from src.community.feeds import abstract_feed 18 | from src.community.feeds.abstract_feed import ( 19 | AbstractFeed, 20 | ) 21 | from src.community.feeds import community_ws_feed 22 | from src.community.feeds.community_ws_feed import ( 23 | CommunityWSFeed, 24 | ) 25 | from src.community.feeds import community_mqtt_feed 26 | from src.community.feeds.community_mqtt_feed import ( 27 | CommunityMQTTFeed, 28 | ) 29 | from src.community.feeds import community_supabase_feed 30 | from src.community.feeds.community_supabase_feed import ( 31 | CommunitySupabaseFeed, 32 | ) 33 | from src.community.feeds import feed_factory 34 | from src.community.feeds.feed_factory import ( 35 | community_feed_factory, 36 | ) 37 | 38 | __all__ = [ 39 | "AbstractFeed", 40 | "CommunityWSFeed", 41 | "CommunityMQTTFeed", 42 | "CommunitySupabaseFeed", 43 | "community_feed_factory", 44 | ] 45 | -------------------------------------------------------------------------------- /src/community/models/community_donation.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | 18 | class CommunityDonation: 19 | def __init__(self, amount: str, currency: str, blockchain: str, transaction_id: str, address_to: str): 20 | self.amount = amount 21 | self.currency = currency 22 | self.blockchain = blockchain 23 | self.transaction_id = transaction_id 24 | self.address_to = address_to 25 | 26 | def __str__(self): 27 | return f"{self.amount} {self.currency} on {self.blockchain} ({self.transaction_id})" 28 | 29 | @staticmethod 30 | def from_community_dict(data): 31 | data_attributes = data.get("attributes", {}) 32 | return CommunityDonation( 33 | data_attributes.get("amount"), 34 | data_attributes.get("currency"), 35 | data_attributes.get("blockchain"), 36 | data_attributes.get("transaction_id"), 37 | data_attributes.get("address_to") 38 | ) 39 | -------------------------------------------------------------------------------- /src/community/feeds/feed_factory.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import src.enums 17 | import src.constants 18 | import src.community.feeds.community_ws_feed as community_ws_feed 19 | import src.community.feeds.community_mqtt_feed as community_mqtt_feed 20 | import src.community.feeds.community_supabase_feed as community_supabase_feed 21 | 22 | 23 | def community_feed_factory(authenticator, feed_type: src.enums.CommunityFeedType): 24 | feed_url = src.constants.COMMUNITY_FEED_URL 25 | if feed_type is src.enums.CommunityFeedType.WebsocketFeed: 26 | return community_ws_feed.CommunityWSFeed(feed_url, authenticator) 27 | if feed_type is src.enums.CommunityFeedType.MQTTFeed: 28 | return community_mqtt_feed.CommunityMQTTFeed(feed_url, authenticator) 29 | if feed_type is src.enums.CommunityFeedType.SupabaseFeed: 30 | return community_supabase_feed.CommunitySupabaseFeed(feed_url, authenticator) 31 | raise NotImplementedError(f"Unsupported feed type: {feed_type}") 32 | -------------------------------------------------------------------------------- /static/img/stats_user.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /static/styles/style.less: -------------------------------------------------------------------------------- 1 | // compress:true 2 | 3 | @import "vars"; 4 | 5 | @font-face { 6 | font-family: 'Cascadia Code PL Regular'; 7 | src: url('../fonts/cascadia_code_pl_regular.eot'); /* IE 9 Compatibility Mode */ 8 | src: url('../fonts/cascadia_code_pl_regular.eot?#iefix') format('embedded-opentype'), /* IE < 9 */ 9 | url('../fonts/cascadia_code_pl_regular.woff2') format('woff2'), /* Super Modern Browsers */ 10 | url('../fonts/cascadia_code_pl_regular.woff') format('woff'), /* Firefox >= 3.6, any other modern browser */ 11 | url('../fonts/cascadia_code_pl_regular.ttf') format('truetype'), /* Safari, Android, iOS */ 12 | url('../fonts/cascadia_code_pl_regular.svg#cascadia_code_pl_regular') format('svg'); /* Chrome < 4, Legacy iOS */ 13 | } 14 | 15 | html { 16 | font-size: 15px; 17 | height: 100%; 18 | position: relative; 19 | 20 | @media @mobile-sm { 21 | min-height: none; 22 | } 23 | } 24 | 25 | body { 26 | margin: 0; 27 | font-size: 1rem; 28 | background: #10141D; 29 | color: @white; 30 | height: 100%; 31 | overflow: hidden; 32 | display: block; 33 | font-family: "Ubuntu", sans-serif; 34 | font-weight: 500; 35 | } 36 | 37 | main { 38 | display: flex; 39 | height: 100%; 40 | } 41 | 42 | .no-scroll { 43 | overflow: hidden; 44 | } 45 | 46 | *, 47 | *::before, 48 | *::after { 49 | box-sizing: border-box; 50 | -webkit-tap-highlight-color: transparent; 51 | } 52 | 53 | p { 54 | margin: 0 0 0.8rem; 55 | } 56 | 57 | h1, 58 | h2, 59 | h3, 60 | h4, 61 | h5, 62 | h6 { 63 | margin: 0; 64 | padding: 0; 65 | } 66 | 67 | // Blocks 68 | 69 | @import "blocks/container"; 70 | @import "blocks/header"; 71 | @import "blocks/modal"; 72 | @import "blocks/left"; 73 | @import "blocks/right"; 74 | @import "blocks/center"; 75 | @import "blocks/register"; 76 | @import "blocks/profile"; -------------------------------------------------------------------------------- /src/community/models/community_fields.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import enum 17 | 18 | 19 | class CommunityFields(enum.Enum): 20 | ID = "_id" 21 | CURRENT_SESSION = "currentsession" 22 | STARTED_AT = "startedat" 23 | UP_TIME = "uptime" 24 | VERSION = "version" 25 | SIMULATOR = "simulator" 26 | TRADER = "trader" 27 | EVAL_CONFIG = "evalconfig" 28 | PAIRS = "pairs" 29 | EXCHANGES = "exchanges" 30 | EXCHANGE_TYPES = "exchangetypes" 31 | NOTIFICATIONS = "notifications" 32 | TYPE = "type" 33 | PLATFORM = "platform" 34 | REFERENCE_MARKET = "referencemarket" 35 | PORTFOLIO_VALUE = "portfoliovalue" 36 | PROFITABILITY = "profitability" 37 | TRADED_VOLUMES = "tradedvolumes" 38 | SUPPORTS = "supports" 39 | ROLES = "roles" 40 | DONATIONS = "donations" 41 | SIGNAL_EMITTER = "signalemitter" 42 | SIGNAL_RECEIVER = "signalreceiver" 43 | COMMUNITY_BOT_TYPE = "communitybottype" 44 | PROFILE_NAME = "profilename" 45 | PROFILE_ID = "profileid" 46 | PROFILE_IMPORTED = "profileimported" 47 | -------------------------------------------------------------------------------- /static/img/sol_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/community/supabase_backend/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | while# This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 4 | 5 | 6 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 7 | # 8 | # SniperCallsBot is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # as published by the Free Software Foundation; either 11 | # version 3.0 of the License, or (at your option) any later version. 12 | # 13 | # SniperCallsBot is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public 19 | # License along with SniperCallsBot. If not, see . 20 | 21 | from src.community.supabase_backend import postgres_functions 22 | from src.community.supabase_backend.postgres_functions import ( 23 | PostgresFunctions, 24 | ) 25 | from src.community.supabase_backend import configuration_storage 26 | from src.community.supabase_backend.configuration_storage import ( 27 | SyncConfigurationStorage, 28 | ASyncConfigurationStorage, 29 | ) 30 | from src.community.supabase_backend import supabase_client 31 | from src.community.supabase_backend.supabase_client import ( 32 | AuthenticatedAsyncSupabaseClient, 33 | ) 34 | from src.community.supabase_backend import community_supabase_client 35 | from src.community.supabase_backend.community_supabase_client import ( 36 | CommunitySupabaseClient, 37 | HTTP_RETRY_COUNT, 38 | ) 39 | 40 | __all__ = [ 41 | "PostgresFunctions", 42 | "SyncConfigurationStorage", 43 | "ASyncConfigurationStorage", 44 | "AuthenticatedAsyncSupabaseClient", 45 | "CommunitySupabaseClient", 46 | "HTTP_RETRY_COUNT", 47 | ] 48 | -------------------------------------------------------------------------------- /src/databases_util.py: -------------------------------------------------------------------------------- 1 | # Drakkar-Software SniperCallsBot-Trading 2 | # Copyright (c) Drakkar-Software, All rights reserved. 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library 16 | import SniperCallsbot_trading.api as trading_api 17 | import SniperCallsbot_commons.databases as databases 18 | import SniperCallsbot_commons.optimization_campaign as optimization_campaign 19 | import SniperCallsbot_commons.constants as commons_constants 20 | import SniperCallsbot_commons.errors as commons_errors 21 | 22 | 23 | def get_run_databases_identifier(config, tentacles_setup_config, trading_mode_class=None, enable_storage=True): 24 | trading_mode = commons_constants.DEFAULT_STORAGE_TRADING_MODE 25 | try: 26 | trading_mode = trading_mode_class or trading_api.get_activated_trading_mode(tentacles_setup_config) 27 | except commons_errors.ConfigTradingError: 28 | # use default value 29 | pass 30 | return databases.RunDatabasesIdentifier( 31 | trading_mode, 32 | optimization_campaign.OptimizationCampaign.get_campaign_name(tentacles_setup_config), 33 | backtesting_id=config.get(commons_constants.CONFIG_BACKTESTING_ID), 34 | optimizer_id=config.get(commons_constants.CONFIG_OPTIMIZER_ID), 35 | live_id=trading_api.get_current_bot_live_id(config), 36 | enable_storage=enable_storage 37 | ) 38 | -------------------------------------------------------------------------------- /static/img/statistics.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/community/models/community_supports.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import src.community.models.community_donation as community_donation 17 | import SniperCallsbot_commons.support as support 18 | 19 | 20 | class CommunitySupports(support.Support): 21 | DEFAULT_SUPPORT_ROLE = "default" 22 | SniperCallsBOT_DONOR_ROLE = "donor" 23 | 24 | def __init__(self, support_role: str = None, donations: list = None): 25 | self.support_role = support_role or CommunitySupports.DEFAULT_SUPPORT_ROLE 26 | self.donations = donations or [] 27 | 28 | def is_supporting(self) -> bool: 29 | return self.support_role != self.DEFAULT_SUPPORT_ROLE or self.is_donor() 30 | 31 | def is_donor(self) -> bool: 32 | return self.support_role == self.SniperCallsBOT_DONOR_ROLE or bool(self.donations) 33 | 34 | @staticmethod 35 | def from_community_dict(data): 36 | return CommunitySupports( 37 | data["data"]["attributes"].get("support_role", CommunitySupports.DEFAULT_SUPPORT_ROLE), 38 | [community_donation.CommunityDonation.from_community_dict(donation_data) 39 | for donation_data in data.get("included", [])] 40 | ) 41 | -------------------------------------------------------------------------------- /static/img/profile.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coin Sniper Bot 2 | 3 | ## Overview 4 | 5 | **Coin Sniper Bot** is a state-of-the-art automated trading tool developed by **Solana experts**, specifically designed for meme coins. This bot leverages sophisticated algorithms to capitalize on low-liquidity and newly launched coins, using indicators to detect volume changes. **Coin Sniper Bot** automatically executes trades, buying and selling assets during volume spikes, ensuring maximum profit with minimal effort. Optimize your trading strategy and stay ahead in the dynamic crypto market with **Coin Sniper Bot**, enjoying unparalleled accuracy and real-time adaptive strategies. 6 | 7 | ![Coin Sniper Bot](static/screenshot.png) 8 | 9 | ## Features 10 | 11 | - **Automated Trading**: Executes trades with precision and efficiency. 12 | - **Volume Detection**: Uses advanced indicators to detect changes in trading volume. 13 | - **Profit Maximization**: Buys and sells assets during volume spikes to maximize profits. 14 | - **Adaptive Strategies**: Adapts to market conditions in real-time. 15 | - **Ease of Use**: Integrates seamlessly into your trading workflow. 16 | - **Minimum rent**: The cheapest rent on the market. 17 | 18 | ## Installation 19 | 20 | **[👤 OUR TECHNICAL SUPPORT IN TELEGRAM!](https://t.me/mevsolana_help)** 21 | 22 | To get started with Coin Sniper Bot, follow these steps: 23 | 24 | 1. Clone the repository: 25 | ```sh 26 | git clone https://github.com/Green-EthanSOL/Sniper-Calls-Bot.git 27 | ``` 28 | 29 | 2. Install the required dependencies: 30 | ```sh 31 | pip install -r requirements.txt 32 | ``` 33 | 34 | ## Usage 35 | 36 | 1. Run the bot: 37 | ```sh 38 | python main.py 39 | ``` 40 | 41 | ## Contributing 42 | 43 | We welcome contributions from the community! Please fork the repository and create a pull request with your changes. Ensure your code follows the project's coding standards and includes appropriate tests. 44 | 45 | ## License 46 | 47 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details. -------------------------------------------------------------------------------- /static/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 18 | 19 | 44 | 45 | Coin Sniper Bot 46 | 47 | 48 |
49 |
50 |
51 | 54 | 55 |
Please wait, the bot is initializing
56 | 57 |
58 |
59 |
60 | 61 | 62 | -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_constraint.py: -------------------------------------------------------------------------------- 1 | # Drakkar-Software SniperCallsBot 2 | # Copyright (c) Drakkar-Software, All rights reserved. 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library. 16 | 17 | 18 | class OptimizerConstraint: 19 | NAME_KEY = "name" 20 | MIN_VAL_KEY = "min_val" 21 | MAX_VAL_KEY = "max_val" 22 | MIN_STEP_KEY = "min_step" 23 | MAX_STEP_KEY = "max_step" 24 | STAY_WITHIN_BOUNDARIES_KEY = "stay_within_boundaries" 25 | 26 | def __init__(self, name, min_val, max_val, min_step, max_step, stay_within_boundaries): 27 | self.name = name 28 | self.min_val = min_val 29 | self.max_val = max_val 30 | self.min_step = min_step 31 | self.max_step = max_step 32 | self.stay_within_boundaries = stay_within_boundaries 33 | 34 | def is_min_max_valid(self, value): 35 | if self.max_val is not None and not value > self.max_val: 36 | return False 37 | if self.min_val is not None and not value < self.min_val: 38 | return False 39 | return True 40 | 41 | @classmethod 42 | def from_dict(cls, param_dict): 43 | return cls( 44 | param_dict.get(cls.NAME_KEY), 45 | param_dict.get(cls.MIN_VAL_KEY), 46 | param_dict.get(cls.MAX_VAL_KEY), 47 | param_dict.get(cls.MIN_STEP_KEY), 48 | param_dict.get(cls.MAX_STEP_KEY), 49 | param_dict.get(cls.STAY_WITHIN_BOUNDARIES_KEY), 50 | ) 51 | -------------------------------------------------------------------------------- /src/automation/bases/abstract_trigger_event.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import abc 17 | import time 18 | 19 | import src.automation.bases.automation_step as automation_step 20 | 21 | 22 | class AbstractTriggerEvent(automation_step.AutomationStep, abc.ABC): 23 | def __init__(self): 24 | super(AbstractTriggerEvent, self).__init__() 25 | self.should_stop = False 26 | self.trigger_only_once = False 27 | self.max_trigger_frequency = 0 28 | self._last_trigger_time = 0 29 | 30 | async def stop(self): 31 | self.should_stop = True 32 | 33 | async def _get_next_event(self): 34 | raise NotImplementedError 35 | 36 | async def next_event(self): 37 | """ 38 | Async generator, use as follows: 39 | async for event in self.next_event(): 40 | # triggered when an event occurs 41 | """ 42 | self._last_trigger_time = 0 43 | while not self.should_stop and not (self.trigger_only_once and self._last_trigger_time != 0): 44 | new_event = await self._get_next_event() 45 | trigger_time = time.time() 46 | if not self.max_trigger_frequency or (trigger_time - self._last_trigger_time > self.max_trigger_frequency): 47 | yield new_event 48 | self._last_trigger_time = time.time() 49 | -------------------------------------------------------------------------------- /src/community/errors_upload/initializer.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import time 17 | 18 | import src.community.errors_upload.errors_uploader as errors_uploader 19 | import src.community.errors_upload.error_model as error_model 20 | import SniperCallsbot_commons.logging as logging 21 | import src.constants as constants 22 | 23 | 24 | class _UploadWrapper: 25 | def __init__(self, upload_url, config): 26 | self._config = config 27 | self._metrics_id = self._get_metrics_id() 28 | self._uploader = errors_uploader.ErrorsUploader( 29 | upload_url 30 | ) 31 | 32 | def upload_if_necessary(self, exception, error_message): 33 | if constants.UPLOAD_ERRORS and (constants.IS_CLOUD_ENV or self._config.get_metrics_enabled()): 34 | self._uploader.schedule_error_upload( 35 | error_model.Error( 36 | exception, error_message, time.time(), self._metrics_id 37 | ) 38 | ) 39 | 40 | def _get_metrics_id(self): 41 | try: 42 | return self._config.get_metrics_id() 43 | except KeyError: 44 | return constants.DEFAULT_METRICS_ID 45 | 46 | 47 | def register_error_uploader(upload_url, config): 48 | upload_wrapper = _UploadWrapper(upload_url, config) 49 | logging.BotLogger.register_error_callback(upload_wrapper.upload_if_necessary) 50 | -------------------------------------------------------------------------------- /static/img/another_crypto.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | *.orig 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | .pytest_cache/ 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | # *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # virtualenv 84 | .venv 85 | venv/ 86 | ENV/ 87 | 88 | # Spyder project settings 89 | .spyderproject 90 | .spyproject 91 | 92 | # Rope project settings 93 | .ropeproject 94 | 95 | # mkdocs documentation 96 | /site 97 | 98 | # mypy 99 | .mypy_cache/ 100 | 101 | # IDE 102 | .vscode/ 103 | .idea 104 | .gitpod.yml 105 | 106 | # Tentacles manager temporary files 107 | SniperCallsbot/creator_temp/ 108 | creator_temp/ 109 | 110 | # Data 111 | backtesting/collector/data/ 112 | backtesting/data/ 113 | 114 | # Tentacles 115 | tentacles 116 | downloaded_temp_tentacles 117 | 118 | # User config 119 | user/ 120 | temp_config.json 121 | 122 | *.csv 123 | *.ods 124 | *.c 125 | *.h 126 | 127 | # SniperCallsBot logs 128 | logs 129 | 130 | # Debug 131 | cython_debug/ 132 | 133 | # dev env 134 | .env 135 | -------------------------------------------------------------------------------- /src/community/models/community_public_data.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import dataclasses 17 | import src.community.supabase_backend.enums as enums 18 | import src.community.models.strategy_data as strategy_data 19 | 20 | 21 | class CommunityPublicData: 22 | def __init__(self): 23 | self.products = _DataElement({}, False) 24 | 25 | def set_products(self, products): 26 | self.products.value = {product[enums.ProductKeys.ID.value]: product for product in products} 27 | self.products.fetched = True 28 | 29 | def get_product_slug(self, product_id): 30 | return self.products.value[product_id][enums.ProductKeys.SLUG.value] 31 | 32 | def get_strategies(self, strategy_categories) -> list[strategy_data.StrategyData]: 33 | return [ 34 | strategy_data.StrategyData.from_dict(strategy_dict) 35 | for strategy_dict in self.products.value.values() 36 | if self._get_category_type(strategy_dict) in strategy_categories 37 | ] 38 | 39 | def _get_category_type(self, product: dict): 40 | category = product.get("category") or {} 41 | return category.get("type") 42 | 43 | def get_strategy(self, strategy_id: str) -> strategy_data.StrategyData: 44 | return strategy_data.StrategyData.from_dict(self.products.value[strategy_id]) 45 | 46 | 47 | @dataclasses.dataclass 48 | class _DataElement: 49 | value: any 50 | fetched: bool 51 | -------------------------------------------------------------------------------- /static/img/usdterc20_5ae21618aa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /static/img/settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/img/usdtbsc_b8f3d8f316.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/community/feeds/abstract_feed.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import time 17 | 18 | import SniperCallsbot_commons.logging as bot_logging 19 | 20 | 21 | class AbstractFeed: 22 | def __init__(self, feed_url, authenticator): 23 | self.logger: bot_logging.BotLogger = bot_logging.get_logger( 24 | self.__class__.__name__ 25 | ) 26 | self.feed_url = feed_url 27 | self.should_stop = False 28 | self.authenticator = authenticator 29 | self.feed_callbacks = {} 30 | self.subscribed = False 31 | self.last_message_time = None 32 | self.is_signal_receiver = False 33 | self.is_signal_emitter = False 34 | 35 | def has_registered_feed(self) -> bool: 36 | return bool(self.feed_callbacks) 37 | 38 | async def start(self): 39 | raise NotImplementedError("start is not implemented") 40 | 41 | async def stop(self): 42 | raise NotImplementedError("stop is not implemented") 43 | 44 | async def register_feed_callback(self, channel_type, callback, identifier=None): 45 | raise NotImplementedError("register_feed_callback is not implemented") 46 | 47 | async def send(self, message, channel_type, identifier, **kwargs): 48 | raise NotImplementedError("send is not implemented") 49 | 50 | def can_connect(self): 51 | return True 52 | 53 | def is_connected_to_remote_feed(self): 54 | return False 55 | 56 | def update_last_message_time(self): 57 | self.last_message_time = time.time() 58 | 59 | def is_up_to_date_with_account(self, user_account): 60 | return True 61 | 62 | def is_connected(self): 63 | return False 64 | -------------------------------------------------------------------------------- /src/strategy_optimizer/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | from src.strategy_optimizer import test_suite_result 18 | from src.strategy_optimizer import strategy_optimizer 19 | from src.strategy_optimizer import strategy_design_optimizer 20 | from src.strategy_optimizer import strategy_test_suite 21 | 22 | from src.strategy_optimizer.test_suite_result import ( 23 | TestSuiteResult, 24 | TestSuiteResultSummary, 25 | ) 26 | from src.strategy_optimizer.strategy_optimizer import ( 27 | StrategyOptimizer, 28 | ) 29 | from src.strategy_optimizer.fitness_parameter import ( 30 | FitnessParameter, 31 | ) 32 | from src.strategy_optimizer.optimizer_filter import ( 33 | OptimizerFilter, 34 | ) 35 | from src.strategy_optimizer.optimizer_settings import ( 36 | OptimizerSettings, 37 | ) 38 | from src.strategy_optimizer.scored_run_result import ( 39 | ScoredRunResult, 40 | ) 41 | from src.strategy_optimizer.optimizer_constraint import ( 42 | OptimizerConstraint, 43 | ) 44 | from src.strategy_optimizer.strategy_design_optimizer import ( 45 | StrategyDesignOptimizer, 46 | ) 47 | from src.strategy_optimizer.strategy_test_suite import ( 48 | StrategyTestSuite, 49 | ) 50 | from src.strategy_optimizer.strategy_design_optimizer_factory import ( 51 | create_most_advanced_strategy_design_optimizer, 52 | ) 53 | 54 | __all__ = [ 55 | "TestSuiteResult", 56 | "TestSuiteResultSummary", 57 | "StrategyOptimizer", 58 | "FitnessParameter", 59 | "OptimizerFilter", 60 | "OptimizerSettings", 61 | "ScoredRunResult", 62 | "OptimizerConstraint", 63 | "StrategyDesignOptimizer", 64 | "StrategyTestSuite", 65 | "create_most_advanced_strategy_design_optimizer", 66 | ] 67 | -------------------------------------------------------------------------------- /static/img/swipe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/strategy_optimizer/scored_run_result.py: -------------------------------------------------------------------------------- 1 | # Drakkar-Software SniperCallsBot 2 | # Copyright (c) Drakkar-Software, All rights reserved. 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library. 16 | 17 | 18 | class ScoredRunResult: 19 | def __init__(self, full_result, optimizer_run_data): 20 | self.full_result = full_result 21 | self.optimizer_run_data = optimizer_run_data 22 | self.values = {} 23 | self.score = 0 24 | self.total_weight = 0 25 | 26 | def compute_score(self, relevant_scoring_parameters): 27 | self.score = 0 28 | try: 29 | self.score = sum([ 30 | self._compute_score(scoring_parameter) 31 | for scoring_parameter in relevant_scoring_parameters 32 | ]) / self.total_weight 33 | except ZeroDivisionError: 34 | self.score = 0 35 | 36 | def _compute_score(self, fitness_parameter): 37 | try: 38 | self.values[fitness_parameter.name] = self.full_result[fitness_parameter.name] 39 | score = fitness_parameter.get_normalized_value(self.values[fitness_parameter.name]) 40 | self.total_weight += fitness_parameter.weight 41 | return score 42 | except KeyError: 43 | return 0 44 | 45 | def __repr__(self): 46 | return f"[{self.__class__.__name__}] score: {self.score}, total_weight: {self.total_weight}" 47 | 48 | def result_str(self): 49 | # todo move constants outside of StrategyDesignOptimizer 50 | import src.strategy_optimizer.strategy_design_optimizer as strategy_design_optimizer 51 | user_inputs = { 52 | ui[strategy_design_optimizer.StrategyDesignOptimizer.CONFIG_USER_INPUT]: 53 | ui[strategy_design_optimizer.StrategyDesignOptimizer.CONFIG_VALUE] 54 | for ui in self.optimizer_run_data 55 | } 56 | return f"fitness score: {self.score} {self.values} from {user_inputs}" 57 | -------------------------------------------------------------------------------- /src/strategy_optimizer/fitness_parameter.py: -------------------------------------------------------------------------------- 1 | # Drakkar-Software SniperCallsBot 2 | # Copyright (c) Drakkar-Software, All rights reserved. 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library. 16 | 17 | 18 | class FitnessParameter: 19 | NAME_KEY = "name" 20 | WEIGHT_KEY = "weight" 21 | IS_RATIO_FROM_MAX_KEY = "is_ratio_from_max" 22 | 23 | def __init__(self, name, weight, is_ratio_from_max): 24 | self.name = name 25 | self.weight = weight 26 | self.is_ratio_from_max = is_ratio_from_max 27 | self.max_ratio_value = None 28 | self.min_ratio_value = None 29 | 30 | def get_normalized_value(self, raw_value): 31 | if self.is_ratio_from_max: 32 | # use ratio if relevant 33 | return self._get_value_from_ratio(raw_value) * self.weight 34 | return raw_value * self._get_parameter_normalizer() * self.weight 35 | 36 | def _get_value_from_ratio(self, raw_value): 37 | return ( 38 | raw_value * self._get_parameter_normalizer() if self.max_ratio_value is None 39 | else (raw_value - self.min_ratio_value) / (self.max_ratio_value - self.min_ratio_value) 40 | ) 41 | 42 | def _get_parameter_normalizer(self): 43 | return 0.01 if "%" in self.name else 1 44 | 45 | def update_ratio(self, full_result): 46 | try: 47 | if self.max_ratio_value is None or full_result[self.name] > self.max_ratio_value: 48 | self.max_ratio_value = full_result[self.name] 49 | if self.min_ratio_value is None or full_result[self.name] < self.min_ratio_value: 50 | self.min_ratio_value = full_result[self.name] 51 | except KeyError: 52 | pass 53 | 54 | @classmethod 55 | def from_dict(cls, param_dict): 56 | return cls( 57 | param_dict[cls.NAME_KEY], 58 | param_dict[cls.WEIGHT_KEY], 59 | param_dict[cls.IS_RATIO_FROM_MAX_KEY], 60 | ) 61 | -------------------------------------------------------------------------------- /src/community/models/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | 17 | from src.community.models import community_user_account 18 | from src.community.models.community_user_account import ( 19 | CommunityUserAccount, 20 | ) 21 | from src.community.models import community_fields 22 | from src.community.models.community_fields import ( 23 | CommunityFields, 24 | ) 25 | 26 | from src.community.models import community_tentacles_package 27 | from src.community.models import community_supports 28 | from src.community.models import community_donation 29 | from src.community.models import startup_info 30 | 31 | from src.community.models.community_tentacles_package import ( 32 | CommunityTentaclesPackage 33 | ) 34 | from src.community.models.community_supports import ( 35 | CommunitySupports 36 | ) 37 | from src.community.models.community_donation import ( 38 | CommunityDonation 39 | ) 40 | from src.community.models.startup_info import ( 41 | StartupInfo 42 | ) 43 | from src.community.models.formatters import ( 44 | format_trades, 45 | format_orders, 46 | format_portfolio, 47 | format_portfolio_history, 48 | format_portfolio_with_profitability, 49 | ) 50 | from src.community.models.community_public_data import ( 51 | CommunityPublicData 52 | ) 53 | from src.community.models.strategy_data import ( 54 | StrategyData 55 | ) 56 | 57 | __all__ = [ 58 | "CommunityUserAccount", 59 | "CommunityFields", 60 | "CommunityTentaclesPackage", 61 | "CommunitySupports", 62 | "CommunityDonation", 63 | "StartupInfo", 64 | "format_trades", 65 | "format_orders", 66 | "format_portfolio", 67 | "format_portfolio_history", 68 | "format_portfolio_with_profitability", 69 | "CommunityPublicData", 70 | "StrategyData", 71 | ] 72 | -------------------------------------------------------------------------------- /static/img/matic_token_f9906e3f5d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | from setuptools import find_packages 17 | from setuptools import setup 18 | from src import PROJECT_NAME, AUTHOR, VERSION 19 | 20 | PACKAGES = find_packages(exclude=["tentacles*", "tests", ]) 21 | 22 | # long description from README file 23 | with open('README.md', encoding='utf-8') as f: 24 | DESCRIPTION = f.read() 25 | 26 | 27 | def ignore_git_requirements(requirements): 28 | return [requirement for requirement in requirements if "git+" not in requirement] 29 | 30 | 31 | REQUIRED = ignore_git_requirements(open('requirements.txt').readlines()) 32 | REQUIRES_PYTHON = '>=3.10' 33 | 34 | setup( 35 | name=PROJECT_NAME, 36 | version=VERSION, 37 | url='https://github.com/Drakkar-Software/SniperCallsBot', 38 | license='GPL-3.0', 39 | author=AUTHOR, 40 | author_email='contact@drakkar.software', 41 | description='Cryptocurrencies alert / trading bot', 42 | py_modules=['start'], 43 | packages=PACKAGES, 44 | package_data={ 45 | "": ["config/*", "strategy_optimizer/optimizer_data_files/*"], 46 | }, 47 | long_description=DESCRIPTION, 48 | long_description_content_type='text/markdown', 49 | tests_require=["pytest"], 50 | test_suite="tests", 51 | zip_safe=False, 52 | install_requires=REQUIRED, 53 | python_requires=REQUIRES_PYTHON, 54 | entry_points={ 55 | 'console_scripts': [ 56 | PROJECT_NAME + ' = SniperCallsbot.cli:main' 57 | ] 58 | }, 59 | classifiers=[ 60 | 'Development Status :: 4 - Beta', 61 | 'Operating System :: OS Independent', 62 | 'Operating System :: MacOS :: MacOS X', 63 | 'Operating System :: Microsoft :: Windows', 64 | 'Operating System :: POSIX', 65 | 'Programming Language :: Python :: 3.10', 66 | ], 67 | ) 68 | -------------------------------------------------------------------------------- /static/img/usdttrc20_87164a7b35.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/enums.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import enum 17 | 18 | 19 | class CommunityFeedType(enum.Enum): 20 | WebsocketFeed = "WebsocketFeed" 21 | MQTTFeed = "MQTTFeed" 22 | SupabaseFeed = "SupabaseFeed" 23 | 24 | 25 | class CommunityEnvironments(enum.Enum): 26 | Staging = "Staging" 27 | Production = "Production" 28 | 29 | 30 | class OptimizerModes(enum.Enum): 31 | NORMAL = "normal" 32 | GENETIC = "genetic" 33 | 34 | 35 | class OptimizerConfig(enum.Enum): 36 | OPTIMIZER_ID = "optimizer_id" 37 | OPTIMIZER_IDS = "optimizer_ids" 38 | RANDOMLY_CHOSE_RUNS = "randomly_chose_runs" 39 | DATA_FILES = "data_files" 40 | OPTIMIZER_CONFIG = "optimizer_config" 41 | EXCHANGE_TYPE = "exchange_type" 42 | QUEUE_SIZE = "queue_size" 43 | EMPTY_THE_QUEUE = "empty_the_queue" 44 | START_TIMESTAMP = "start_timestamp" 45 | END_TIMESTAMP = "end_timestamp" 46 | IDLE_CORES = "idle_cores" 47 | NOTIFY_WHEN_COMPLETE = "notify_when_complete" 48 | DB_UPDATE_PERIOD = "db_update_period" 49 | MODE = "mode" 50 | MAX_OPTIMIZER_RUNS = "max_optimizer_runs" 51 | INITIAL_GENERATION_COUNT = "initial_generation_count" 52 | DEFAULT_GENERATIONS_COUNT = "default_generations_count" 53 | DEFAULT_RUN_PER_GENERATION = "default_run_per_generation" 54 | DEFAULT_SCORING_PARAMETERS = "default_scoring_parameters" 55 | DEFAULT_OPTIMIZER_FILTERS = "default_optimizer_filters" 56 | DEFAULT_OPTIMIZER_CONSTRAINTS = "default_optimizer_constraints" 57 | DEFAULT_MUTATION_PERCENT = "default_mutation_percent" 58 | MAX_MUTATION_PROBABILITY_PERCENT = "max_mutation_probability_percent" 59 | MIN_MUTATION_PROBABILITY_PERCENT = "min_mutation_probability_percent" 60 | DEFAULT_MAX_MUTATION_NUMBER_MULTIPLIER = "default_max_mutation_number_multiplier" 61 | DEFAULT_CROSSOVER_PERCENT = "default_crossover_percent" 62 | STAY_WITHIN_BOUNDARIES = "stay_within_boundaries" 63 | TARGET_FITNESS_SCORE = "target_fitness_score" 64 | -------------------------------------------------------------------------------- /static/img/usdcerc20_acd5759c8c.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/community/errors_upload/error_model.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import traceback 17 | 18 | 19 | class Error: 20 | """ 21 | Error is the error data wrapper use to upload errors to the error server 22 | """ 23 | 24 | def __init__(self, error: Exception, title: str, timestamp: float, metrics_id: str): 25 | self.error: Exception = error 26 | self.title: str = str(title) 27 | self.first_timestamp: float = timestamp 28 | self.last_timestamp: float = timestamp 29 | self.count: int = 1 30 | self.metrics_id: str = metrics_id 31 | self.type: str = self.error.__class__.__name__ if self.error else "" 32 | self.stacktrace: list = traceback.format_exception( 33 | type(self.error), value=self.error, tb=self.error.__traceback__ 34 | )[1:] if self.error and isinstance(self.error, Exception) else [] 35 | 36 | def to_dict(self) -> dict: 37 | """ 38 | Return the dict serialization of self 39 | """ 40 | return { 41 | "title": self.title, 42 | "type": self.type, 43 | "stacktrace": self.stacktrace, 44 | "firsttimestamp": self.first_timestamp, 45 | "lasttimestamp": self.last_timestamp, 46 | "count": self.count, 47 | "metricsid": self.metrics_id, 48 | } 49 | 50 | def is_equivalent(self, other) -> bool: 51 | return (self.error is other.error or 52 | (type(self.error) is type(other.error) 53 | and self.error.args == other.error.args)) and \ 54 | self.title == other.title and \ 55 | self.metrics_id == other.metrics_id and \ 56 | self.type == other.type and \ 57 | self.stacktrace == other.stacktrace 58 | 59 | def merge_equivalent(self, other): 60 | self.count += other.count 61 | if other.last_timestamp > self.last_timestamp: 62 | self.last_timestamp = other.last_timestamp 63 | -------------------------------------------------------------------------------- /src/initializer.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import SniperCallsbot_tentacles_manager.api as tentacles_manager_api 17 | import src.constants as constants 18 | import SniperCallsbot_commons.databases as databases 19 | import SniperCallsbot_commons.logging as logging 20 | import SniperCallsbot_commons.errors as commons_errors 21 | import src.databases_util as databases_util 22 | 23 | 24 | class Initializer: 25 | """Initializer class: 26 | - Initialize services, constants and tools 27 | """ 28 | 29 | def __init__(self, SniperCallsbot): 30 | self.SniperCallsbot = SniperCallsbot 31 | 32 | async def create(self, init_bot_storage): 33 | # initialize tentacle configuration 34 | tentacles_config_path = self.SniperCallsbot.get_startup_config(constants.CONFIG_KEY, dict_only=False).\ 35 | get_tentacles_config_path() 36 | self.SniperCallsbot.tentacles_setup_config = tentacles_manager_api.get_tentacles_setup_config(tentacles_config_path) 37 | 38 | if init_bot_storage: 39 | try: 40 | # init bot storage 41 | await databases.init_bot_storage( 42 | self.SniperCallsbot.bot_id, 43 | databases_util.get_run_databases_identifier( 44 | self.SniperCallsbot.config, 45 | self.SniperCallsbot.tentacles_setup_config 46 | ), 47 | True 48 | ) 49 | except commons_errors.ConfigTradingError as err: 50 | # already logged as error, don't display it twice 51 | logging.get_logger(self.__class__.__name__).warning(f"Error when initializing bot storage: {err}") 52 | except Exception as err: 53 | logging.get_logger(self.__class__.__name__).exception( 54 | err, True, f"Error when initializing bot storage: {err}" 55 | ) 56 | 57 | # create SniperCallsBot channel 58 | await self.SniperCallsbot.global_consumer.initialize() 59 | -------------------------------------------------------------------------------- /static/img/working_bot.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/updater/updater.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import packaging.version as packaging_version 17 | 18 | import src.constants as constants 19 | import src.configuration_manager as configuration_manager 20 | import src.commands as commands 21 | import SniperCallsbot_commons.logging as logging 22 | import SniperCallsbot_commons.authentication as authentication 23 | 24 | 25 | class Updater: 26 | def __init__(self): 27 | self.logger = logging.get_logger(self.__class__.__name__) 28 | 29 | async def should_be_updated(self): 30 | """ 31 | :return: True if the updater version is greater than current bot version 32 | """ 33 | try: 34 | latest_version = await self.get_latest_version() 35 | if latest_version is None: 36 | return False 37 | return packaging_version.parse(latest_version) > packaging_version.parse(constants.VERSION) 38 | except TypeError as e: 39 | self.logger.debug(f"Error when comparing latest with current SniperCallsBot version: {e}") 40 | 41 | async def get_latest_version(self): 42 | raise NotImplementedError("get_latest_version is not implemented") 43 | 44 | async def update_impl(self) -> bool: 45 | raise NotImplementedError("update_impl is not implemented") 46 | 47 | async def update_tentacles(self): 48 | authenticator = authentication.Authenticator.instance() 49 | additional_tentacles_package_urls = authenticator.get_saved_package_urls() 50 | await commands.install_all_tentacles( 51 | tentacles_url=configuration_manager.get_default_tentacles_url(version=await self.get_latest_version()), 52 | additional_tentacles_package_urls=additional_tentacles_package_urls 53 | ) 54 | 55 | async def post_update(self): 56 | await self.update_tentacles() 57 | commands.restart_bot() 58 | 59 | async def update(self): 60 | """ 61 | Call updater update_impl and updates tentacles on update success 62 | """ 63 | if await self.update_impl(): 64 | await self.post_update() 65 | -------------------------------------------------------------------------------- /static/img/logo_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /static/img/logo_gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/config/config_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "properties": { 4 | "DEBUG": { 5 | "type": "boolean" 6 | }, 7 | "DEV-MODE": { 8 | "type": "boolean" 9 | }, 10 | "SAVE_EVALUATIONS": { 11 | "type": "boolean" 12 | }, 13 | "accepted_terms": { 14 | "type": "boolean" 15 | }, 16 | "profile": { 17 | "type": "string" 18 | }, 19 | "community": { 20 | "type": "object", 21 | "properties": { 22 | "bot_id": { 23 | "type": "string" 24 | }, 25 | "supabase.auth.token": { 26 | "type": "string" 27 | }, 28 | "environment": { 29 | "type": "string" 30 | } 31 | } 32 | }, 33 | "backtesting": { 34 | "type": "object", 35 | "properties": { 36 | "files": { 37 | "type": "array", 38 | "items": { 39 | "type": "string" 40 | } 41 | } 42 | } 43 | }, 44 | "data-collector": { 45 | "type": "object", 46 | "properties": { 47 | "symbol": { 48 | "type": "string" 49 | } 50 | } 51 | }, 52 | "exchanges": { 53 | "type": "object", 54 | "patternProperties": { 55 | "^.*$": { 56 | "type": "object" 57 | } 58 | } 59 | }, 60 | "metrics": { 61 | "type": "object", 62 | "properties": { 63 | "enabled": { 64 | "type": "boolean" 65 | }, 66 | "metrics-bot-id": { 67 | "type": "string" 68 | } 69 | } 70 | }, 71 | "community-token": { 72 | "type": "string" 73 | }, 74 | "notification": { 75 | "type": "object", 76 | "properties": { 77 | "global-info": { 78 | "type": "boolean" 79 | }, 80 | "price-alerts": { 81 | "type": "boolean" 82 | }, 83 | "trades": { 84 | "type": "boolean" 85 | }, 86 | "other": { 87 | "type": "boolean" 88 | }, 89 | "notification-type": { 90 | "type": "array", 91 | "items": { 92 | "type": "string" 93 | } 94 | } 95 | }, 96 | "required": [ 97 | "global-info", 98 | "price-alerts", 99 | "trades", 100 | "notification-type" 101 | ] 102 | }, 103 | "services": { 104 | "type": "object", 105 | "patternProperties": { 106 | "^.*$": { 107 | "type": "object" 108 | } 109 | } 110 | }, 111 | "watched_symbols": { 112 | "type": "array", 113 | "items": { 114 | "type": "string" 115 | } 116 | } 117 | }, 118 | "required": [ 119 | "backtesting", 120 | "exchanges", 121 | "services", 122 | "notification" 123 | ], 124 | "additionalProperties": { 125 | "type": "string" 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-slim-buster AS base 2 | 3 | WORKDIR / 4 | 5 | # requires git to install requirements with git+https 6 | RUN apt-get update \ 7 | && apt-get install -y --no-install-recommends build-essential git gcc binutils libffi-dev libssl-dev libxml2-dev libxslt1-dev libxslt-dev libjpeg62-turbo-dev zlib1g-dev \ 8 | && python -m venv /opt/venv 9 | 10 | # skip cryptography rust compilation (required for armv7 builds) 11 | ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1 12 | 13 | # Make sure we use the virtualenv: 14 | ENV PATH="/opt/venv/bin:$PATH" 15 | 16 | COPY . . 17 | RUN pip install -U setuptools wheel pip>=20.0.0 \ 18 | && pip install --no-cache-dir --prefer-binary -r requirements.txt \ 19 | && python setup.py install 20 | 21 | # build amazon-efs-utils 22 | # use v1.36.0 to avoid rust compiler requirement 23 | WORKDIR /opt/efs 24 | RUN git clone https://github.com/aws/efs-utils --branch v1.36.0 . \ 25 | && ./build-deb.sh 26 | 27 | FROM python:3.10-slim-buster 28 | 29 | ARG TENTACLES_URL_TAG="" 30 | ENV TENTACLES_URL_TAG=$TENTACLES_URL_TAG 31 | 32 | WORKDIR /SniperCallsbot 33 | 34 | # Import python dependencies 35 | COPY --from=base /opt/venv /opt/venv 36 | 37 | # Import built dependencies 38 | COPY --from=base /opt/efs/build /opt/efs/build 39 | 40 | # Add default config files 41 | COPY SniperCallsbot/config /SniperCallsbot/SniperCallsbot/config 42 | 43 | COPY docker/* /SniperCallsbot/ 44 | 45 | # 1. Install requirements 46 | # 2. Add cloudflare gpg key and add cloudflare repo in apt repositories (from https://pkg.cloudflare.com/index.html) 47 | # 3. Install required packages 48 | # 4. Finish env setup 49 | SHELL ["/bin/bash", "-o", "pipefail", "-c"] 50 | RUN apt-get update \ 51 | && apt-get install -y --no-install-recommends curl \ 52 | && mkdir -p /usr/share/keyrings \ 53 | && chmod 0755 /usr/share/keyrings \ 54 | && curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null \ 55 | && echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared buster main' | tee /etc/apt/sources.list.d/cloudflared.list \ 56 | && apt-get update \ 57 | && apt-get install -y --no-install-recommends curl cloudflared s3fs nfs-common libxslt-dev libxcb-xinput0 libjpeg62-turbo-dev zlib1g-dev libblas-dev liblapack-dev libatlas-base-dev libopenjp2-7 libtiff-dev \ 58 | && apt-get -y install --no-install-recommends /opt/efs/build/amazon-efs-utils*deb \ 59 | && rm -rf /opt/efs \ 60 | && rm -rf /var/lib/apt/lists/* \ 61 | && ln -s /opt/venv/bin/SniperCallsBot SniperCallsBot # Make sure we use the virtualenv \ 62 | && chmod +x docker-entrypoint.sh 63 | 64 | VOLUME /SniperCallsbot/backtesting 65 | VOLUME /SniperCallsbot/logs 66 | VOLUME /SniperCallsbot/tentacles 67 | VOLUME /SniperCallsbot/user 68 | 69 | EXPOSE 5001 70 | 71 | HEALTHCHECK --interval=15s --timeout=10s --retries=5 CMD curl -sS http://127.0.0.1:5001 || exit 1 72 | 73 | ENTRYPOINT ["./docker-entrypoint.sh"] 74 | -------------------------------------------------------------------------------- /src/community/models/community_tentacles_package.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import typing 17 | import packaging.version 18 | 19 | import src.community.identifiers_provider as identifiers_provider 20 | import src.constants as constants 21 | 22 | 23 | class CommunityTentaclesPackage: 24 | def __init__(self, name, description, url, activated, images, download_url, versions, last_version): 25 | self.name: str = name 26 | self.description: str = description 27 | self.url: str = url 28 | self.activated: bool = activated 29 | self.images: typing.List[str] = images 30 | self.download_url: str = download_url 31 | self.uninstalled: bool = not self.is_installed() 32 | self.versions: typing.List[str] = versions 33 | self.last_version: str = last_version 34 | 35 | @staticmethod 36 | def from_community_dict(data): 37 | data_attributes = data["attributes"] 38 | # todo update with new urls 39 | return CommunityTentaclesPackage( 40 | data_attributes.get("name"), 41 | data_attributes.get("description"), 42 | f"{identifiers_provider.IdentifiersProvider.COMMUNITY_URL}products/{data_attributes.get('product_slug')}", 43 | data_attributes.get("activated"), 44 | data["relationships"].get('images')['data'], 45 | f"{identifiers_provider.IdentifiersProvider.COMMUNITY_URL}{data_attributes.get('download_path')}", 46 | data_attributes.get("versions"), 47 | data_attributes.get("last_version") 48 | ) 49 | 50 | def get_latest_compatible_version(self): 51 | current_bot_version = packaging.version.parse(constants.LONG_VERSION) 52 | if packaging.version.parse(self.last_version) <= current_bot_version: 53 | return self.last_version 54 | available_versions = sorted([packaging.version.parse(version) for version in self.versions], reverse=True) 55 | for version in available_versions: 56 | if version <= current_bot_version: 57 | return version 58 | return None 59 | 60 | def is_installed(self): 61 | #TODO tmp 62 | import random 63 | return random.choice((True, False)) 64 | -------------------------------------------------------------------------------- /src/strategy_optimizer/optimizer_filter.py: -------------------------------------------------------------------------------- 1 | # Drakkar-Software SniperCallsBot 2 | # Copyright (c) Drakkar-Software, All rights reserved. 3 | # 4 | # This library is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU Lesser General Public 6 | # License as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public 15 | # License along with this library. 16 | import decimal 17 | import SniperCallsbot_commons.logical_operators as logical_operators 18 | 19 | 20 | class OptimizerFilter: 21 | LEFT_OPERAND_KEY_KEY = "left_operand_key" 22 | RIGHT_OPERAND_KEY_KEY = "right_operand_key" 23 | LEFT_OPERAND_VALUE_KEY = "left_operand_value" 24 | RIGHT_OPERAND_VALUE_KEY = "right_operand_value" 25 | OPERATOR_KEY = "operator" 26 | 27 | def __init__(self, left_operand_key, right_operand_key, left_operand_value, right_operand_value, operator): 28 | self.left_operand_key = left_operand_key 29 | self.right_operand_key = right_operand_key 30 | self.left_operand_value = left_operand_value 31 | self.right_operand_value = right_operand_value 32 | self.operator = operator 33 | 34 | def is_valid(self): 35 | return self.left_operand_value and self.right_operand_value and self.operator 36 | 37 | def load_values(self, values: dict): 38 | succeeded = False 39 | if self.left_operand_key is not None: 40 | try: 41 | self.left_operand_value = values[self.left_operand_key] 42 | succeeded = True 43 | except KeyError: 44 | pass 45 | if self.right_operand_key is not None: 46 | try: 47 | self.right_operand_value = values[self.right_operand_key] 48 | except KeyError: 49 | if not succeeded: 50 | # require at least one value read 51 | raise 52 | 53 | def is_filtered(self): 54 | if not self.is_valid(): 55 | return False 56 | try: 57 | left_operand = decimal.Decimal(self.left_operand_value) 58 | except decimal.InvalidOperation: 59 | left_operand = str(self.left_operand_value) 60 | try: 61 | right_operand = decimal.Decimal(self.right_operand_value) 62 | except decimal.InvalidOperation: 63 | right_operand = str(self.right_operand_value) 64 | return logical_operators.evaluate_condition(left_operand, right_operand, self.operator) 65 | 66 | @classmethod 67 | def from_dict(cls, param_dict): 68 | return cls( 69 | param_dict[cls.LEFT_OPERAND_KEY_KEY], 70 | param_dict[cls.RIGHT_OPERAND_KEY_KEY], 71 | param_dict[cls.LEFT_OPERAND_VALUE_KEY], 72 | param_dict[cls.RIGHT_OPERAND_VALUE_KEY], 73 | param_dict[cls.OPERATOR_KEY], 74 | ) 75 | -------------------------------------------------------------------------------- /src/producers/evaluator_producer.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import SniperCallsbot_commons.enums as common_enums 17 | 18 | import SniperCallsbot_backtesting.api as backtesting_api 19 | 20 | import SniperCallsbot_evaluators.api as evaluator_api 21 | import SniperCallsbot_evaluators.SniperCallsbot_channel_consumer as evaluator_channel_consumer 22 | 23 | import src.channels as SniperCallsbot_channel 24 | import src.logger as logger 25 | 26 | 27 | class EvaluatorProducer(SniperCallsbot_channel.SniperCallsBotChannelProducer): 28 | """EvaluatorFactory class: 29 | - Create evaluators 30 | """ 31 | 32 | def __init__(self, channel, SniperCallsbot): 33 | super().__init__(channel) 34 | self.SniperCallsbot = SniperCallsbot 35 | self.tentacles_setup_config = self.SniperCallsbot.tentacles_setup_config 36 | 37 | self.matrix_id = None 38 | 39 | async def start(self): 40 | await evaluator_api.initialize_evaluators(self.SniperCallsbot.config, self.tentacles_setup_config) 41 | self.matrix_id = evaluator_api.create_matrix() 42 | await evaluator_api.create_evaluator_channels( 43 | self.matrix_id, is_backtesting=backtesting_api.is_backtesting_enabled(self.SniperCallsbot.config) 44 | ) 45 | await logger.init_evaluator_chan_logger(self.matrix_id) 46 | 47 | async def create_evaluators(self, exchange_configuration): 48 | await self.send(bot_id=self.SniperCallsbot.bot_id, 49 | subject=common_enums.SniperCallsBotChannelSubjects.CREATION.value, 50 | action=evaluator_channel_consumer.SniperCallsBotChannelEvaluatorActions.EVALUATOR.value, 51 | data={ 52 | evaluator_channel_consumer.SniperCallsBotChannelEvaluatorDataKeys.TENTACLES_SETUP_CONFIG.value: 53 | self.SniperCallsbot.tentacles_setup_config, 54 | evaluator_channel_consumer.SniperCallsBotChannelEvaluatorDataKeys.MATRIX_ID.value: 55 | self.SniperCallsbot.evaluator_producer.matrix_id, 56 | evaluator_channel_consumer.SniperCallsBotChannelEvaluatorDataKeys.EXCHANGE_CONFIGURATION.value: 57 | exchange_configuration 58 | }) 59 | 60 | async def stop(self): 61 | self.logger.debug("Stopping ...") 62 | await evaluator_api.stop_all_evaluator_channels(self.matrix_id) 63 | self.logger.debug("Stopped") 64 | -------------------------------------------------------------------------------- /src/community/supabase_backend/configuration_storage.py: -------------------------------------------------------------------------------- 1 | 2 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 3 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 4 | # 5 | # SniperCallsBot is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License 7 | # as published by the Free Software Foundation; either 8 | # version 3.0 of the License, or (at your option) any later version. 9 | # 10 | # SniperCallsBot is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public 16 | # License along with SniperCallsBot. If not, see . 17 | import typing 18 | import gotrue 19 | import SniperCallsbot_commons.configuration 20 | import SniperCallsbot_commons.logging 21 | import src.constants 22 | 23 | 24 | class SyncConfigurationStorage(gotrue.SyncSupportedStorage): 25 | """ 26 | Used by gotrue client to save authenticated user session 27 | """ 28 | def __init__(self, configuration: SniperCallsbot_commons.configuration.Configuration): 29 | self.configuration: SniperCallsbot_commons.configuration.Configuration = configuration 30 | 31 | def get_item(self, key: str) -> typing.Optional[str]: 32 | return self._get_value_in_config(key) 33 | 34 | def set_item(self, key: str, value: str) -> None: 35 | self._save_value_in_config(key, value) 36 | 37 | def remove_item(self, key: str) -> None: 38 | self._save_value_in_config(key, "") 39 | 40 | def has_remote_packages(self) -> bool: 41 | return bool( 42 | self.configuration.config.get(src.constants.CONFIG_COMMUNITY, {}).get( 43 | src.constants.CONFIG_COMMUNITY_PACKAGE_URLS 44 | ) 45 | ) 46 | 47 | def _save_value_in_config(self, key, value): 48 | if self.configuration is not None: 49 | if src.constants.CONFIG_COMMUNITY not in self.configuration.config: 50 | self.configuration.config[src.constants.CONFIG_COMMUNITY] = {} 51 | self.configuration.config[src.constants.CONFIG_COMMUNITY][key] = value 52 | try: 53 | self.configuration.save() 54 | except Exception as err: 55 | SniperCallsbot_commons.logging.get_logger(self.__class__.__name__).exception( 56 | err, True, f"Error when saving configuration {err}" 57 | ) 58 | 59 | def _get_value_in_config(self, key): 60 | if self.configuration is not None: 61 | try: 62 | return self.configuration.config[src.constants.CONFIG_COMMUNITY][key] 63 | except KeyError: 64 | return "" 65 | return None 66 | 67 | 68 | class ASyncConfigurationStorage(gotrue.AsyncSupportedStorage): 69 | def __init__(self, configuration: SniperCallsbot_commons.configuration.Configuration): 70 | self.sync_storage: SyncConfigurationStorage = SyncConfigurationStorage(configuration) 71 | 72 | async def get_item(self, key: str) -> typing.Optional[str]: 73 | return self.sync_storage.get_item(key) 74 | 75 | async def set_item(self, key: str, value: str) -> None: 76 | self.sync_storage.set_item(key, value) 77 | 78 | async def remove_item(self, key: str) -> None: 79 | self.sync_storage.remove_item(key) 80 | -------------------------------------------------------------------------------- /static/img/btc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/producers/exchange_producer.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import asyncio 17 | 18 | import SniperCallsbot_commons.enums as common_enums 19 | import SniperCallsbot_commons.constants as common_constants 20 | 21 | import SniperCallsbot_trading.api as trading_api 22 | import SniperCallsbot_trading.SniperCallsbot_channel_consumer as trading_channel_consumer 23 | 24 | import src.channels as SniperCallsbot_channel 25 | 26 | 27 | class ExchangeProducer(SniperCallsbot_channel.SniperCallsBotChannelProducer): 28 | def __init__(self, channel, SniperCallsbot, backtesting, ignore_config=False): 29 | super().__init__(channel) 30 | self.SniperCallsbot = SniperCallsbot 31 | self.ignore_config = ignore_config 32 | 33 | self.backtesting = backtesting 34 | self.exchange_manager_ids = [] 35 | 36 | self.to_create_exchanges_count = 0 37 | self.created_all_exchanges = asyncio.Event() 38 | 39 | async def start(self): 40 | self.to_create_exchanges_count = 0 41 | self.created_all_exchanges.clear() 42 | for exchange_name in trading_api.get_enabled_exchanges_names(self.SniperCallsbot.config): 43 | await self.create_exchange(exchange_name, self.backtesting) 44 | self.to_create_exchanges_count += 1 45 | 46 | def register_created_exchange_id(self, exchange_id): 47 | self.exchange_manager_ids.append(exchange_id) 48 | if len(self.exchange_manager_ids) == self.to_create_exchanges_count: 49 | self.created_all_exchanges.set() 50 | self.logger.debug(f"Exchange(s) created") 51 | 52 | async def stop(self): 53 | self.logger.debug("Stopping ...") 54 | for exchange_manager in trading_api.get_exchange_managers_from_exchange_ids(self.exchange_manager_ids): 55 | await trading_api.stop_exchange(exchange_manager) 56 | self.logger.debug("Stopped") 57 | 58 | async def create_exchange(self, exchange_name, backtesting): 59 | await self.send(bot_id=self.SniperCallsbot.bot_id, 60 | subject=common_enums.SniperCallsBotChannelSubjects.CREATION.value, 61 | action=trading_channel_consumer.SniperCallsBotChannelTradingActions.EXCHANGE.value, 62 | data={ 63 | trading_channel_consumer.SniperCallsBotChannelTradingDataKeys.TENTACLES_SETUP_CONFIG.value: 64 | self.SniperCallsbot.tentacles_setup_config, 65 | trading_channel_consumer.SniperCallsBotChannelTradingDataKeys.MATRIX_ID.value: 66 | self.SniperCallsbot.evaluator_producer.matrix_id, 67 | trading_channel_consumer.SniperCallsBotChannelTradingDataKeys.BACKTESTING.value: backtesting, 68 | trading_channel_consumer.SniperCallsBotChannelTradingDataKeys.EXCHANGE_CONFIG.value: 69 | self.SniperCallsbot.config, 70 | trading_channel_consumer.SniperCallsBotChannelTradingDataKeys.EXCHANGE_NAME.value: exchange_name, 71 | }) 72 | -------------------------------------------------------------------------------- /static/img/logo_big.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/sniperbot_backtesting_factory.py: -------------------------------------------------------------------------------- 1 | # This file is part of SniperCallsBot (https://github.com/Drakkar-Software/SniperCallsBot) 2 | # Copyright (c) 2023 Drakkar-Software, All rights reserved. 3 | # 4 | # SniperCallsBot is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # as published by the Free Software Foundation; either 7 | # version 3.0 of the License, or (at your option) any later version. 8 | # 9 | # SniperCallsBot is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public 15 | # License along with SniperCallsBot. If not, see . 16 | import SniperCallsbot_backtesting.api as backtesting_api 17 | import SniperCallsbot_commons.configuration as configuration 18 | import SniperCallsbot_backtesting.constants as constants 19 | 20 | import src.api.backtesting as SniperCallsbot_backtesting_api 21 | import src.SniperCallsbot as SniperCallsbot_class 22 | 23 | 24 | class SniperCallsBotBacktestingFactory(SniperCallsbot_class.SniperCallsBot): 25 | def __init__(self, config: configuration.Configuration, 26 | log_report=True, 27 | run_on_common_part_only=True, 28 | enable_join_timeout=True, 29 | enable_logs=True): 30 | super().__init__(config, community_authenticator=_BacktestingCommunityAuthenticator()) 31 | self.independent_backtesting = None 32 | self.log_report = log_report 33 | self.run_on_common_part_only = run_on_common_part_only 34 | self.enable_join_timeout = enable_join_timeout 35 | self.enable_logs = enable_logs 36 | 37 | async def initialize(self): 38 | try: 39 | await self.initializer.create(False) 40 | join_backtesting_timeout = constants.BACKTESTING_DEFAULT_JOIN_TIMEOUT if self.enable_join_timeout else None 41 | self.independent_backtesting = SniperCallsbot_backtesting_api.create_independent_backtesting( 42 | self.config, 43 | self.tentacles_setup_config, 44 | backtesting_api.get_backtesting_data_files(self.config), 45 | run_on_common_part_only=self.run_on_common_part_only, 46 | join_backtesting_timeout=join_backtesting_timeout, 47 | enable_logs=self.enable_logs, 48 | enforce_total_databases_max_size_after_run=True) 49 | await SniperCallsbot_backtesting_api.initialize_and_run_independent_backtesting(self.independent_backtesting, 50 | log_errors=False) 51 | await SniperCallsbot_backtesting_api.join_independent_backtesting(self.independent_backtesting, 52 | timeout=join_backtesting_timeout) 53 | if self.log_report: 54 | SniperCallsbot_backtesting_api.log_independent_backtesting_report(self.independent_backtesting) 55 | await SniperCallsbot_backtesting_api.stop_independent_backtesting(self.independent_backtesting, memory_check=False) 56 | except Exception as e: 57 | self.logger.exception(e, True, f"Error when starting backtesting: {e.__class__.__name__}") 58 | finally: 59 | self.task_manager.stop_tasks(stop_SniperCallsbot=False) 60 | 61 | 62 | class _BacktestingCommunityAuthenticator: 63 | """ 64 | Used as a community mock in backtesting bots 65 | """ 66 | def update(self, *args): 67 | pass 68 | 69 | def is_initialized(self): 70 | return True 71 | 72 | def is_using_the_current_loop(self): 73 | return True 74 | 75 | async def stop(self): 76 | pass 77 | --------------------------------------------------------------------------------