Merge pull request #1024 from freqtrade/feature/webhook
Feature/webhook
This commit is contained in:
commit
7134c15e86
74
README.md
74
README.md
@ -4,13 +4,12 @@
|
|||||||
[![Coverage Status](https://coveralls.io/repos/github/freqtrade/freqtrade/badge.svg?branch=develop&service=github)](https://coveralls.io/github/freqtrade/freqtrade?branch=develop)
|
[![Coverage Status](https://coveralls.io/repos/github/freqtrade/freqtrade/badge.svg?branch=develop&service=github)](https://coveralls.io/github/freqtrade/freqtrade?branch=develop)
|
||||||
[![Maintainability](https://api.codeclimate.com/v1/badges/5737e6d668200b7518ff/maintainability)](https://codeclimate.com/github/freqtrade/freqtrade/maintainability)
|
[![Maintainability](https://api.codeclimate.com/v1/badges/5737e6d668200b7518ff/maintainability)](https://codeclimate.com/github/freqtrade/freqtrade/maintainability)
|
||||||
|
|
||||||
|
Simple High frequency trading bot for crypto currencies designed to support multi exchanges and be controlled via Telegram.
|
||||||
Simple High frequency trading bot for crypto currencies designed to
|
|
||||||
support multi exchanges and be controlled via Telegram.
|
|
||||||
|
|
||||||
![freqtrade](https://raw.githubusercontent.com/freqtrade/freqtrade/develop/docs/assets/freqtrade-screenshot.png)
|
![freqtrade](https://raw.githubusercontent.com/freqtrade/freqtrade/develop/docs/assets/freqtrade-screenshot.png)
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
This software is for educational purposes only. Do not risk money which
|
This software is for educational purposes only. Do not risk money which
|
||||||
you are afraid to lose. USE THE SOFTWARE AT YOUR OWN RISK. THE AUTHORS
|
you are afraid to lose. USE THE SOFTWARE AT YOUR OWN RISK. THE AUTHORS
|
||||||
AND ALL AFFILIATES ASSUME NO RESPONSIBILITY FOR YOUR TRADING RESULTS.
|
AND ALL AFFILIATES ASSUME NO RESPONSIBILITY FOR YOUR TRADING RESULTS.
|
||||||
@ -23,18 +22,18 @@ We strongly recommend you to have coding and Python knowledge. Do not
|
|||||||
hesitate to read the source code and understand the mechanism of this bot.
|
hesitate to read the source code and understand the mechanism of this bot.
|
||||||
|
|
||||||
## Exchange marketplaces supported
|
## Exchange marketplaces supported
|
||||||
|
|
||||||
- [X] [Bittrex](https://bittrex.com/)
|
- [X] [Bittrex](https://bittrex.com/)
|
||||||
- [X] [Binance](https://www.binance.com/)
|
- [X] [Binance](https://www.binance.com/)
|
||||||
- [ ] [113 others to tests](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_
|
- [ ] [113 others to tests](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- [x] **Based on Python 3.6+**: For botting on any operating system -
|
|
||||||
Windows, macOS and Linux
|
- [x] **Based on Python 3.6+**: For botting on any operating system - Windows, macOS and Linux
|
||||||
- [x] **Persistence**: Persistence is achieved through sqlite
|
- [x] **Persistence**: Persistence is achieved through sqlite
|
||||||
- [x] **Dry-run**: Run the bot without playing money.
|
- [x] **Dry-run**: Run the bot without playing money.
|
||||||
- [x] **Backtesting**: Run a simulation of your buy/sell strategy.
|
- [x] **Backtesting**: Run a simulation of your buy/sell strategy.
|
||||||
- [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell
|
- [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell strategy parameters with real exchange data.
|
||||||
strategy parameters with real exchange data.
|
|
||||||
- [x] **Whitelist crypto-currencies**: Select which crypto-currency you want to trade.
|
- [x] **Whitelist crypto-currencies**: Select which crypto-currency you want to trade.
|
||||||
- [x] **Blacklist crypto-currencies**: Select which crypto-currency you want to avoid.
|
- [x] **Blacklist crypto-currencies**: Select which crypto-currency you want to avoid.
|
||||||
- [x] **Manageable via Telegram**: Manage the bot with Telegram
|
- [x] **Manageable via Telegram**: Manage the bot with Telegram
|
||||||
@ -43,38 +42,43 @@ strategy parameters with real exchange data.
|
|||||||
- [x] **Performance status report**: Provide a performance status of your current trades.
|
- [x] **Performance status report**: Provide a performance status of your current trades.
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Quick start](#quick-start)
|
- [Quick start](#quick-start)
|
||||||
- [Documentations](https://github.com/freqtrade/freqtrade/blob/develop/docs/index.md)
|
- [Documentations](https://github.com/freqtrade/freqtrade/blob/develop/docs/index.md)
|
||||||
- [Installation](https://github.com/freqtrade/freqtrade/blob/develop/docs/installation.md)
|
- [Installation](https://github.com/freqtrade/freqtrade/blob/develop/docs/installation.md)
|
||||||
- [Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md)
|
- [Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md)
|
||||||
- [Strategy Optimization](https://github.com/freqtrade/freqtrade/blob/develop/docs/bot-optimization.md)
|
- [Strategy Optimization](https://github.com/freqtrade/freqtrade/blob/develop/docs/bot-optimization.md)
|
||||||
- [Backtesting](https://github.com/freqtrade/freqtrade/blob/develop/docs/backtesting.md)
|
- [Backtesting](https://github.com/freqtrade/freqtrade/blob/develop/docs/backtesting.md)
|
||||||
- [Hyperopt](https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md)
|
- [Hyperopt](https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md)
|
||||||
- [Basic Usage](#basic-usage)
|
- [Basic Usage](#basic-usage)
|
||||||
- [Bot commands](#bot-commands)
|
- [Bot commands](#bot-commands)
|
||||||
- [Telegram RPC commands](#telegram-rpc-commands)
|
- [Telegram RPC commands](#telegram-rpc-commands)
|
||||||
- [Support](#support)
|
- [Support](#support)
|
||||||
- [Help](#help--slack)
|
- [Help](#help--slack)
|
||||||
- [Bugs](#bugs--issues)
|
- [Bugs](#bugs--issues)
|
||||||
- [Feature Requests](#feature-requests)
|
- [Feature Requests](#feature-requests)
|
||||||
- [Pull Requests](#pull-requests)
|
- [Pull Requests](#pull-requests)
|
||||||
- [Requirements](#requirements)
|
- [Requirements](#requirements)
|
||||||
- [Min hardware required](#min-hardware-required)
|
- [Min hardware required](#min-hardware-required)
|
||||||
- [Software requirements](#software-requirements)
|
- [Software requirements](#software-requirements)
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
Freqtrade provides a Linux/macOS script to install all dependencies and help you to configure the bot.
|
Freqtrade provides a Linux/macOS script to install all dependencies and help you to configure the bot.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone git@github.com:freqtrade/freqtrade.git
|
git clone git@github.com:freqtrade/freqtrade.git
|
||||||
git checkout develop
|
git checkout develop
|
||||||
cd freqtrade
|
cd freqtrade
|
||||||
./setup.sh --install
|
./setup.sh --install
|
||||||
```
|
```
|
||||||
|
|
||||||
_Windows installation is explained in [Installation doc](https://github.com/freqtrade/freqtrade/blob/develop/docs/installation.md)_
|
_Windows installation is explained in [Installation doc](https://github.com/freqtrade/freqtrade/blob/develop/docs/installation.md)_
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
We invite you to read the bot documentation to ensure you understand how the bot is working.
|
We invite you to read the bot documentation to ensure you understand how the bot is working.
|
||||||
|
|
||||||
- [Index](https://github.com/freqtrade/freqtrade/blob/develop/docs/index.md)
|
- [Index](https://github.com/freqtrade/freqtrade/blob/develop/docs/index.md)
|
||||||
- [Installation](https://github.com/freqtrade/freqtrade/blob/develop/docs/installation.md)
|
- [Installation](https://github.com/freqtrade/freqtrade/blob/develop/docs/installation.md)
|
||||||
- [Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md)
|
- [Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md)
|
||||||
@ -86,7 +90,6 @@ We invite you to read the bot documentation to ensure you understand how the bot
|
|||||||
- [Backtesting](https://github.com/freqtrade/freqtrade/blob/develop/docs/backtesting.md)
|
- [Backtesting](https://github.com/freqtrade/freqtrade/blob/develop/docs/backtesting.md)
|
||||||
- [Hyperopt](https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md)
|
- [Hyperopt](https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md)
|
||||||
|
|
||||||
|
|
||||||
## Basic Usage
|
## Basic Usage
|
||||||
|
|
||||||
### Bot commands
|
### Bot commands
|
||||||
@ -125,17 +128,15 @@ optional arguments:
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Telegram RPC commands
|
### Telegram RPC commands
|
||||||
Telegram is not mandatory. However, this is a great way to control your
|
|
||||||
bot. More details on our
|
Telegram is not mandatory. However, this is a great way to control your bot. More details on our [documentation](https://github.com/freqtrade/freqtrade/blob/develop/docs/index.md)
|
||||||
[documentation](https://github.com/freqtrade/freqtrade/blob/develop/docs/index.md)
|
|
||||||
|
|
||||||
- `/start`: Starts the trader
|
- `/start`: Starts the trader
|
||||||
- `/stop`: Stops the trader
|
- `/stop`: Stops the trader
|
||||||
- `/status [table]`: Lists all open trades
|
- `/status [table]`: Lists all open trades
|
||||||
- `/count`: Displays number of open trades
|
- `/count`: Displays number of open trades
|
||||||
- `/profit`: Lists cumulative profit from all finished trades
|
- `/profit`: Lists cumulative profit from all finished trades
|
||||||
- `/forcesell <trade_id>|all`: Instantly sells the given trade
|
- `/forcesell <trade_id>|all`: Instantly sells the given trade (Ignoring `minimum_roi`).
|
||||||
(Ignoring `minimum_roi`).
|
|
||||||
- `/performance`: Show performance of each finished trade grouped by pair
|
- `/performance`: Show performance of each finished trade grouped by pair
|
||||||
- `/balance`: Show account balance per currency
|
- `/balance`: Show account balance per currency
|
||||||
- `/daily <n>`: Shows profit or loss per day, over the last n days
|
- `/daily <n>`: Shows profit or loss per day, over the last n days
|
||||||
@ -144,20 +145,23 @@ bot. More details on our
|
|||||||
|
|
||||||
|
|
||||||
## Development branches
|
## Development branches
|
||||||
The project is currently setup in two main branches:
|
|
||||||
- `develop` - This branch has often new features, but might also cause
|
|
||||||
breaking changes.
|
|
||||||
- `master` - This branch contains the latest stable release. The bot
|
|
||||||
'should' be stable on this branch, and is generally well tested.
|
|
||||||
|
|
||||||
|
The project is currently setup in two main branches:
|
||||||
|
|
||||||
|
- `develop` - This branch has often new features, but might also cause breaking changes.
|
||||||
|
- `master` - This branch contains the latest stable release. The bot 'should' be stable on this branch, and is generally well tested.
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
### Help / Slack
|
### Help / Slack
|
||||||
|
|
||||||
For any questions not covered by the documentation or for further
|
For any questions not covered by the documentation or for further
|
||||||
information about the bot, we encourage you to join our slack channel.
|
information about the bot, we encourage you to join our slack channel.
|
||||||
|
|
||||||
- [Click here to join Slack channel](https://join.slack.com/t/highfrequencybot/shared_invite/enQtMjQ5NTM0OTYzMzY3LWMxYzE3M2MxNDdjMGM3ZTYwNzFjMGIwZGRjNTc3ZGU3MGE3NzdmZGMwNmU3NDM5ZTNmM2Y3NjRiNzk4NmM4OGE).
|
- [Click here to join Slack channel](https://join.slack.com/t/highfrequencybot/shared_invite/enQtMjQ5NTM0OTYzMzY3LWMxYzE3M2MxNDdjMGM3ZTYwNzFjMGIwZGRjNTc3ZGU3MGE3NzdmZGMwNmU3NDM5ZTNmM2Y3NjRiNzk4NmM4OGE).
|
||||||
|
|
||||||
### [Bugs / Issues](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue)
|
### [Bugs / Issues](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue)
|
||||||
|
|
||||||
If you discover a bug in the bot, please
|
If you discover a bug in the bot, please
|
||||||
[search our issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue)
|
[search our issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue)
|
||||||
first. If it hasn't been reported, please
|
first. If it hasn't been reported, please
|
||||||
@ -166,6 +170,7 @@ ensure you follow the template guide so that our team can assist you as
|
|||||||
quickly as possible.
|
quickly as possible.
|
||||||
|
|
||||||
### [Feature Requests](https://github.com/freqtrade/freqtrade/labels/enhancement)
|
### [Feature Requests](https://github.com/freqtrade/freqtrade/labels/enhancement)
|
||||||
|
|
||||||
Have you a great idea to improve the bot you want to share? Please,
|
Have you a great idea to improve the bot you want to share? Please,
|
||||||
first search if this feature was not [already discussed](https://github.com/freqtrade/freqtrade/labels/enhancement).
|
first search if this feature was not [already discussed](https://github.com/freqtrade/freqtrade/labels/enhancement).
|
||||||
If it hasn't been requested, please
|
If it hasn't been requested, please
|
||||||
@ -174,6 +179,7 @@ and ensure you follow the template guide so that it does not get lost
|
|||||||
in the bug reports.
|
in the bug reports.
|
||||||
|
|
||||||
### [Pull Requests](https://github.com/freqtrade/freqtrade/pulls)
|
### [Pull Requests](https://github.com/freqtrade/freqtrade/pulls)
|
||||||
|
|
||||||
Feel like our bot is missing a feature? We welcome your pull requests!
|
Feel like our bot is missing a feature? We welcome your pull requests!
|
||||||
Please read our
|
Please read our
|
||||||
[Contributing document](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
[Contributing document](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
||||||
@ -181,16 +187,18 @@ to understand the requirements before sending your pull-requests.
|
|||||||
|
|
||||||
**Note** before starting any major new feature work, *please open an issue describing what you are planning to do* or talk to us on [Slack](https://join.slack.com/t/highfrequencybot/shared_invite/enQtMjQ5NTM0OTYzMzY3LWMxYzE3M2MxNDdjMGM3ZTYwNzFjMGIwZGRjNTc3ZGU3MGE3NzdmZGMwNmU3NDM5ZTNmM2Y3NjRiNzk4NmM4OGE). This will ensure that interested parties can give valuable feedback on the feature, and let others know that you are working on it.
|
**Note** before starting any major new feature work, *please open an issue describing what you are planning to do* or talk to us on [Slack](https://join.slack.com/t/highfrequencybot/shared_invite/enQtMjQ5NTM0OTYzMzY3LWMxYzE3M2MxNDdjMGM3ZTYwNzFjMGIwZGRjNTc3ZGU3MGE3NzdmZGMwNmU3NDM5ZTNmM2Y3NjRiNzk4NmM4OGE). This will ensure that interested parties can give valuable feedback on the feature, and let others know that you are working on it.
|
||||||
|
|
||||||
**Important:** Always create your PR against the `develop` branch, not
|
**Important:** Always create your PR against the `develop` branch, not `master`.
|
||||||
`master`.
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
### Min hardware required
|
### Min hardware required
|
||||||
|
|
||||||
To run this bot we recommend you a cloud instance with a minimum of:
|
To run this bot we recommend you a cloud instance with a minimum of:
|
||||||
* Minimal (advised) system requirements: 2GB RAM, 1GB disk space, 2vCPU
|
|
||||||
|
- Minimal (advised) system requirements: 2GB RAM, 1GB disk space, 2vCPU
|
||||||
|
|
||||||
### Software requirements
|
### Software requirements
|
||||||
|
|
||||||
- [Python 3.6.x](http://docs.python-guide.org/en/latest/starting/installation/)
|
- [Python 3.6.x](http://docs.python-guide.org/en/latest/starting/installation/)
|
||||||
- [pip](https://pip.pypa.io/en/stable/installing/)
|
- [pip](https://pip.pypa.io/en/stable/installing/)
|
||||||
- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
|
- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
|
||||||
|
@ -41,6 +41,11 @@ The table below will list all configuration parameters.
|
|||||||
| `telegram.enabled` | true | Yes | Enable or not the usage of Telegram.
|
| `telegram.enabled` | true | Yes | Enable or not the usage of Telegram.
|
||||||
| `telegram.token` | token | No | Your Telegram bot token. Only required if `telegram.enabled` is `true`.
|
| `telegram.token` | token | No | Your Telegram bot token. Only required if `telegram.enabled` is `true`.
|
||||||
| `telegram.chat_id` | chat_id | No | Your personal Telegram account id. Only required if `telegram.enabled` is `true`.
|
| `telegram.chat_id` | chat_id | No | Your personal Telegram account id. Only required if `telegram.enabled` is `true`.
|
||||||
|
| `webhook.enabled` | false | No | Enable useage of Webhook notifications
|
||||||
|
| `webhook.url` | false | No | URL for the webhook. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
|
||||||
|
| `webhook.webhookbuy` | false | No | Payload to send on buy. Only required if `webhook.enabled` is `true`. See the [webhook documentationV](webhook-config.md) for more details.
|
||||||
|
| `webhook.webhooksell` | false | No | Payload to send on sell. Only required if `webhook.enabled` is `true`. See the [webhook documentationV](webhook-config.md) for more details.
|
||||||
|
| `webhook.webhookstatus` | false | No | Payload to send on status calls. Only required if `webhook.enabled` is `true`. See the [webhook documentationV](webhook-config.md) for more details.
|
||||||
| `db_url` | `sqlite:///tradesv3.sqlite` | No | Declares database URL to use. NOTE: This defaults to `sqlite://` if `dry_run` is `True`.
|
| `db_url` | `sqlite:///tradesv3.sqlite` | No | Declares database URL to use. NOTE: This defaults to `sqlite://` if `dry_run` is `True`.
|
||||||
| `initial_state` | running | No | Defines the initial application state. More information below.
|
| `initial_state` | running | No | Defines the initial application state. More information below.
|
||||||
| `strategy` | DefaultStrategy | No | Defines Strategy class to use.
|
| `strategy` | DefaultStrategy | No | Defines Strategy class to use.
|
||||||
|
@ -27,6 +27,7 @@ Pull-request. Do not hesitate to reach us on
|
|||||||
- [Test your strategy with Backtesting](https://github.com/freqtrade/freqtrade/blob/develop/docs/backtesting.md)
|
- [Test your strategy with Backtesting](https://github.com/freqtrade/freqtrade/blob/develop/docs/backtesting.md)
|
||||||
- [Find optimal parameters with Hyperopt](https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md)
|
- [Find optimal parameters with Hyperopt](https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md)
|
||||||
- [Control the bot with telegram](https://github.com/freqtrade/freqtrade/blob/develop/docs/telegram-usage.md)
|
- [Control the bot with telegram](https://github.com/freqtrade/freqtrade/blob/develop/docs/telegram-usage.md)
|
||||||
|
- [Receive notifications via webhook](https://github.com/freqtrade/freqtrade/blob/develop/docs/webhook-config.md)
|
||||||
- [Contribute to the project](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
- [Contribute to the project](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
||||||
- [How to contribute](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
- [How to contribute](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
||||||
- [Run tests & Check PEP8 compliance](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
- [Run tests & Check PEP8 compliance](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
|
||||||
|
74
docs/webhook-config.md
Normal file
74
docs/webhook-config.md
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Webhook usage
|
||||||
|
|
||||||
|
This page explains how to configure your bot to talk to webhooks.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Enable webhooks by adding a webhook-section to your configuration file, and setting `webhook.enabled` to `true`.
|
||||||
|
|
||||||
|
Sample configuration (tested using IFTTT).
|
||||||
|
|
||||||
|
```json
|
||||||
|
"webhook": {
|
||||||
|
"enabled": true,
|
||||||
|
"url": "https://maker.ifttt.com/trigger/<YOUREVENT>/with/key/<YOURKEY>/",
|
||||||
|
"webhookbuy": {
|
||||||
|
"value1": "Buying {pair}",
|
||||||
|
"value2": "limit {limit:8f}",
|
||||||
|
"value3": "{stake_amount:8f} {stake_currency}"
|
||||||
|
},
|
||||||
|
"webhooksell": {
|
||||||
|
"value1": "Selling {pair}",
|
||||||
|
"value2": "limit {limit:8f}",
|
||||||
|
"value3": "profit: {profit_amount:8f} {stake_currency}"
|
||||||
|
},
|
||||||
|
"webhookstatus": {
|
||||||
|
"value1": "Status: {status}",
|
||||||
|
"value2": "",
|
||||||
|
"value3": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
The url in `webhook.url` should point to the correct url for your webhook. If you're using [IFTTT](https://ifttt.com) (as shown in the sample above) please insert our event and key to the url.
|
||||||
|
|
||||||
|
Different payloads can be configured for different events. Not all fields are necessary, but you should configure at least one of the dicts, otherwise the webhook will never be called.
|
||||||
|
|
||||||
|
### Webhookbuy
|
||||||
|
|
||||||
|
The fields in `webhook.webhookbuy` are filled when the bot executes a buy. Parameters are filled using string.format.
|
||||||
|
Possible parameters are:
|
||||||
|
|
||||||
|
* exchange
|
||||||
|
* pair
|
||||||
|
* market_url
|
||||||
|
* limit
|
||||||
|
* stake_amount
|
||||||
|
* stake_amount_fiat
|
||||||
|
* stake_currency
|
||||||
|
* fiat_currency
|
||||||
|
|
||||||
|
### Webhooksell
|
||||||
|
|
||||||
|
The fields in `webhook.webhooksell` are filled when the bot sells a trade. Parameters are filled using string.format.
|
||||||
|
Possible parameters are:
|
||||||
|
|
||||||
|
* exchange
|
||||||
|
* pair
|
||||||
|
* gain
|
||||||
|
* market_url
|
||||||
|
* limit
|
||||||
|
* amount
|
||||||
|
* open_rate
|
||||||
|
* current_rate
|
||||||
|
* profit_amount
|
||||||
|
* profit_percent
|
||||||
|
* profit_fiat
|
||||||
|
* stake_currency
|
||||||
|
* fiat_currency
|
||||||
|
|
||||||
|
### Webhookstatus
|
||||||
|
|
||||||
|
The fields in `webhook.webhookstatus` are used for regular status messages (Started / Stopped / ...). Parameters are filled using string.format.
|
||||||
|
|
||||||
|
The only possible value here is `{status}`.
|
@ -100,6 +100,15 @@ CONF_SCHEMA = {
|
|||||||
},
|
},
|
||||||
'required': ['enabled', 'token', 'chat_id']
|
'required': ['enabled', 'token', 'chat_id']
|
||||||
},
|
},
|
||||||
|
'webhook': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'enabled': {'type': 'boolean'},
|
||||||
|
'webhookbuy': {'type': 'object'},
|
||||||
|
'webhooksell': {'type': 'object'},
|
||||||
|
'webhookstatus': {'type': 'object'},
|
||||||
|
},
|
||||||
|
},
|
||||||
'db_url': {'type': 'string'},
|
'db_url': {'type': 'string'},
|
||||||
'initial_state': {'type': 'string', 'enum': ['running', 'stopped']},
|
'initial_state': {'type': 'string', 'enum': ['running', 'stopped']},
|
||||||
'internals': {
|
'internals': {
|
||||||
|
@ -19,8 +19,7 @@ from freqtrade.analyze import Analyze
|
|||||||
from freqtrade.exchange import Exchange
|
from freqtrade.exchange import Exchange
|
||||||
from freqtrade.fiat_convert import CryptoToFiatConverter
|
from freqtrade.fiat_convert import CryptoToFiatConverter
|
||||||
from freqtrade.persistence import Trade
|
from freqtrade.persistence import Trade
|
||||||
from freqtrade.rpc import RPCMessageType
|
from freqtrade.rpc import RPCManager, RPCMessageType
|
||||||
from freqtrade.rpc import RPCManager
|
|
||||||
from freqtrade.state import State
|
from freqtrade.state import State
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -23,6 +23,12 @@ class RPCManager(object):
|
|||||||
from freqtrade.rpc.telegram import Telegram
|
from freqtrade.rpc.telegram import Telegram
|
||||||
self.registered_modules.append(Telegram(freqtrade))
|
self.registered_modules.append(Telegram(freqtrade))
|
||||||
|
|
||||||
|
# Enable Webhook
|
||||||
|
if freqtrade.config.get('webhook', {}).get('enabled', False):
|
||||||
|
logger.info('Enabling rpc.webhook ...')
|
||||||
|
from freqtrade.rpc.webhook import Webhook
|
||||||
|
self.registered_modules.append(Webhook(freqtrade))
|
||||||
|
|
||||||
def cleanup(self) -> None:
|
def cleanup(self) -> None:
|
||||||
""" Stops all enabled rpc modules """
|
""" Stops all enabled rpc modules """
|
||||||
logger.info('Cleaning up rpc modules ...')
|
logger.info('Cleaning up rpc modules ...')
|
||||||
|
66
freqtrade/rpc/webhook.py
Normal file
66
freqtrade/rpc/webhook.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
"""
|
||||||
|
This module manages webhook communication
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from requests import post, RequestException
|
||||||
|
|
||||||
|
from freqtrade.rpc import RPC, RPCMessageType
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
logger.debug('Included module rpc.webhook ...')
|
||||||
|
|
||||||
|
|
||||||
|
class Webhook(RPC):
|
||||||
|
""" This class handles all webhook communication """
|
||||||
|
|
||||||
|
def __init__(self, freqtrade) -> None:
|
||||||
|
"""
|
||||||
|
Init the Webhook class, and init the super class RPC
|
||||||
|
:param freqtrade: Instance of a freqtrade bot
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
super().__init__(freqtrade)
|
||||||
|
|
||||||
|
self._config = freqtrade.config
|
||||||
|
self._url = self._config['webhook']['url']
|
||||||
|
|
||||||
|
def cleanup(self) -> None:
|
||||||
|
"""
|
||||||
|
Cleanup pending module resources.
|
||||||
|
This will do nothing for webhooks, they will simply not be called anymore
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def send_msg(self, msg: Dict[str, Any]) -> None:
|
||||||
|
""" Send a message to telegram channel """
|
||||||
|
try:
|
||||||
|
|
||||||
|
if msg['type'] == RPCMessageType.BUY_NOTIFICATION:
|
||||||
|
valuedict = self._config['webhook'].get('webhookbuy', None)
|
||||||
|
elif msg['type'] == RPCMessageType.SELL_NOTIFICATION:
|
||||||
|
valuedict = self._config['webhook'].get('webhooksell', None)
|
||||||
|
elif msg['type'] == RPCMessageType.STATUS_NOTIFICATION:
|
||||||
|
valuedict = self._config['webhook'].get('webhookstatus', None)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError('Unknown message type: {}'.format(msg['type']))
|
||||||
|
if not valuedict:
|
||||||
|
logger.info("Message type %s not configured for webhooks", msg['type'])
|
||||||
|
return
|
||||||
|
|
||||||
|
payload = {key: value.format(**msg) for (key, value) in valuedict.items()}
|
||||||
|
self._send_msg(payload)
|
||||||
|
except KeyError as exc:
|
||||||
|
logger.exception("Problem calling Webhook. Please check your webhook configuration. "
|
||||||
|
"Exception: %s", exc)
|
||||||
|
|
||||||
|
def _send_msg(self, payload: dict) -> None:
|
||||||
|
"""do the actual call to the webhook"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
post(self._url, data=payload)
|
||||||
|
except RequestException as exc:
|
||||||
|
logger.warning("Could not call webhook url. Exception: %s", exc)
|
@ -127,3 +127,33 @@ def test_send_msg_telegram_enabled(mocker, default_conf, caplog) -> None:
|
|||||||
|
|
||||||
assert log_has("Sending rpc message: {'type': status, 'status': 'test'}", caplog.record_tuples)
|
assert log_has("Sending rpc message: {'type': status, 'status': 'test'}", caplog.record_tuples)
|
||||||
assert telegram_mock.call_count == 1
|
assert telegram_mock.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_webhook_disabled(mocker, default_conf, caplog) -> None:
|
||||||
|
""" Test _init() method with Webhook disabled """
|
||||||
|
caplog.set_level(logging.DEBUG)
|
||||||
|
|
||||||
|
conf = deepcopy(default_conf)
|
||||||
|
conf['telegram']['enabled'] = False
|
||||||
|
conf['webhook'] = {'enabled': False}
|
||||||
|
|
||||||
|
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, conf))
|
||||||
|
|
||||||
|
assert not log_has('Enabling rpc.webhook ...', caplog.record_tuples)
|
||||||
|
assert rpc_manager.registered_modules == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_webhook_enabled(mocker, default_conf, caplog) -> None:
|
||||||
|
"""
|
||||||
|
Test _init() method with Webhook enabled
|
||||||
|
"""
|
||||||
|
caplog.set_level(logging.DEBUG)
|
||||||
|
default_conf['telegram']['enabled'] = False
|
||||||
|
default_conf['webhook'] = {'enabled': True, 'url': "https://DEADBEEF.com"}
|
||||||
|
|
||||||
|
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, default_conf))
|
||||||
|
|
||||||
|
assert log_has('Enabling rpc.webhook ...', caplog.record_tuples)
|
||||||
|
len_modules = len(rpc_manager.registered_modules)
|
||||||
|
assert len_modules == 1
|
||||||
|
assert 'webhook' in [mod.name for mod in rpc_manager.registered_modules]
|
||||||
|
179
freqtrade/tests/rpc/test_rpc_webhook.py
Normal file
179
freqtrade/tests/rpc/test_rpc_webhook.py
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from requests import RequestException
|
||||||
|
|
||||||
|
|
||||||
|
from freqtrade.rpc import RPCMessageType
|
||||||
|
from freqtrade.rpc.webhook import Webhook
|
||||||
|
from freqtrade.tests.conftest import get_patched_freqtradebot, log_has
|
||||||
|
|
||||||
|
|
||||||
|
def get_webhook_dict() -> dict:
|
||||||
|
return {
|
||||||
|
"enabled": True,
|
||||||
|
"url": "https://maker.ifttt.com/trigger/freqtrade_test/with/key/c764udvJ5jfSlswVRukZZ2/",
|
||||||
|
"webhookbuy": {
|
||||||
|
"value1": "Buying {pair}",
|
||||||
|
"value2": "limit {limit:8f}",
|
||||||
|
"value3": "{stake_amount:8f} {stake_currency}"
|
||||||
|
},
|
||||||
|
"webhooksell": {
|
||||||
|
"value1": "Selling {pair}",
|
||||||
|
"value2": "limit {limit:8f}",
|
||||||
|
"value3": "profit: {profit_amount:8f} {stake_currency}"
|
||||||
|
},
|
||||||
|
"webhookstatus": {
|
||||||
|
"value1": "Status: {status}",
|
||||||
|
"value2": "",
|
||||||
|
"value3": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test__init__(mocker, default_conf):
|
||||||
|
"""
|
||||||
|
Test __init__() method
|
||||||
|
"""
|
||||||
|
default_conf['webhook'] = {'enabled': True, 'url': "https://DEADBEEF.com"}
|
||||||
|
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
||||||
|
assert webhook._config == default_conf
|
||||||
|
|
||||||
|
|
||||||
|
def test_cleanup(default_conf, mocker) -> None:
|
||||||
|
"""
|
||||||
|
Test cleanup() method - not needed for webhook
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_msg(default_conf, mocker):
|
||||||
|
""" Test send_msg for Webhook rpc class"""
|
||||||
|
default_conf["webhook"] = get_webhook_dict()
|
||||||
|
msg_mock = MagicMock()
|
||||||
|
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||||
|
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
||||||
|
msg = {
|
||||||
|
'type': RPCMessageType.BUY_NOTIFICATION,
|
||||||
|
'exchange': 'Bittrex',
|
||||||
|
'pair': 'ETH/BTC',
|
||||||
|
'market_url': "http://mockedurl/ETH_BTC",
|
||||||
|
'limit': 0.005,
|
||||||
|
'stake_amount': 0.8,
|
||||||
|
'stake_amount_fiat': 500,
|
||||||
|
'stake_currency': 'BTC',
|
||||||
|
'fiat_currency': 'EUR'
|
||||||
|
}
|
||||||
|
msg_mock = MagicMock()
|
||||||
|
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||||
|
webhook.send_msg(msg=msg)
|
||||||
|
assert msg_mock.call_count == 1
|
||||||
|
assert (msg_mock.call_args[0][0]["value1"] ==
|
||||||
|
default_conf["webhook"]["webhookbuy"]["value1"].format(**msg))
|
||||||
|
assert (msg_mock.call_args[0][0]["value2"] ==
|
||||||
|
default_conf["webhook"]["webhookbuy"]["value2"].format(**msg))
|
||||||
|
assert (msg_mock.call_args[0][0]["value3"] ==
|
||||||
|
default_conf["webhook"]["webhookbuy"]["value3"].format(**msg))
|
||||||
|
# Test sell
|
||||||
|
msg_mock = MagicMock()
|
||||||
|
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||||
|
msg = {
|
||||||
|
'type': RPCMessageType.SELL_NOTIFICATION,
|
||||||
|
'exchange': 'Bittrex',
|
||||||
|
'pair': 'ETH/BTC',
|
||||||
|
'gain': "profit",
|
||||||
|
'market_url': "http://mockedurl/ETH_BTC",
|
||||||
|
'limit': 0.005,
|
||||||
|
'amount': 0.8,
|
||||||
|
'open_rate': 0.004,
|
||||||
|
'current_rate': 0.005,
|
||||||
|
'profit_amount': 0.001,
|
||||||
|
'profit_percent': 0.20,
|
||||||
|
'stake_currency': 'BTC',
|
||||||
|
}
|
||||||
|
webhook.send_msg(msg=msg)
|
||||||
|
assert msg_mock.call_count == 1
|
||||||
|
assert (msg_mock.call_args[0][0]["value1"] ==
|
||||||
|
default_conf["webhook"]["webhooksell"]["value1"].format(**msg))
|
||||||
|
assert (msg_mock.call_args[0][0]["value2"] ==
|
||||||
|
default_conf["webhook"]["webhooksell"]["value2"].format(**msg))
|
||||||
|
assert (msg_mock.call_args[0][0]["value3"] ==
|
||||||
|
default_conf["webhook"]["webhooksell"]["value3"].format(**msg))
|
||||||
|
|
||||||
|
# Test notification
|
||||||
|
msg = {
|
||||||
|
'type': RPCMessageType.STATUS_NOTIFICATION,
|
||||||
|
'status': 'Unfilled sell order for BTC cancelled due to timeout'
|
||||||
|
}
|
||||||
|
msg_mock = MagicMock()
|
||||||
|
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||||
|
webhook.send_msg(msg)
|
||||||
|
assert msg_mock.call_count == 1
|
||||||
|
assert (msg_mock.call_args[0][0]["value1"] ==
|
||||||
|
default_conf["webhook"]["webhookstatus"]["value1"].format(**msg))
|
||||||
|
assert (msg_mock.call_args[0][0]["value2"] ==
|
||||||
|
default_conf["webhook"]["webhookstatus"]["value2"].format(**msg))
|
||||||
|
assert (msg_mock.call_args[0][0]["value3"] ==
|
||||||
|
default_conf["webhook"]["webhookstatus"]["value3"].format(**msg))
|
||||||
|
|
||||||
|
|
||||||
|
def test_exception_send_msg(default_conf, mocker, caplog):
|
||||||
|
"""Test misconfigured notification"""
|
||||||
|
default_conf["webhook"] = get_webhook_dict()
|
||||||
|
default_conf["webhook"]["webhookbuy"] = None
|
||||||
|
|
||||||
|
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
||||||
|
webhook.send_msg({'type': RPCMessageType.BUY_NOTIFICATION})
|
||||||
|
assert log_has(f"Message type {RPCMessageType.BUY_NOTIFICATION} not configured for webhooks",
|
||||||
|
caplog.record_tuples)
|
||||||
|
|
||||||
|
default_conf["webhook"] = get_webhook_dict()
|
||||||
|
default_conf["webhook"]["webhookbuy"]["value1"] = "{DEADBEEF:8f}"
|
||||||
|
msg_mock = MagicMock()
|
||||||
|
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||||
|
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
||||||
|
msg = {
|
||||||
|
'type': RPCMessageType.BUY_NOTIFICATION,
|
||||||
|
'exchange': 'Bittrex',
|
||||||
|
'pair': 'ETH/BTC',
|
||||||
|
'market_url': "http://mockedurl/ETH_BTC",
|
||||||
|
'limit': 0.005,
|
||||||
|
'stake_amount': 0.8,
|
||||||
|
'stake_amount_fiat': 500,
|
||||||
|
'stake_currency': 'BTC',
|
||||||
|
'fiat_currency': 'EUR'
|
||||||
|
}
|
||||||
|
webhook.send_msg(msg)
|
||||||
|
assert log_has("Problem calling Webhook. Please check your webhook configuration. "
|
||||||
|
"Exception: 'DEADBEEF'", caplog.record_tuples)
|
||||||
|
|
||||||
|
msg_mock = MagicMock()
|
||||||
|
mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock)
|
||||||
|
msg = {
|
||||||
|
'type': 'DEADBEEF',
|
||||||
|
'status': 'whatever'
|
||||||
|
}
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
webhook.send_msg(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def test__send_msg(default_conf, mocker, caplog):
|
||||||
|
"""Test internal method - calling the actual api"""
|
||||||
|
|
||||||
|
default_conf["webhook"] = get_webhook_dict()
|
||||||
|
webhook = Webhook(get_patched_freqtradebot(mocker, default_conf))
|
||||||
|
msg = {'value1': 'DEADBEEF',
|
||||||
|
'value2': 'ALIVEBEEF',
|
||||||
|
'value3': 'FREQTRADE'}
|
||||||
|
post = MagicMock()
|
||||||
|
mocker.patch("freqtrade.rpc.webhook.post", post)
|
||||||
|
webhook._send_msg(msg)
|
||||||
|
|
||||||
|
assert post.call_count == 1
|
||||||
|
assert post.call_args[1] == {'data': msg}
|
||||||
|
assert post.call_args[0] == (default_conf['webhook']['url'], )
|
||||||
|
|
||||||
|
post = MagicMock(side_effect=RequestException)
|
||||||
|
mocker.patch("freqtrade.rpc.webhook.post", post)
|
||||||
|
webhook._send_msg(msg)
|
||||||
|
assert log_has('Could not call webhook url. Exception: ', caplog.record_tuples)
|
Loading…
Reference in New Issue
Block a user