Merge pull request #33 from nullart/nullartHFT

Order book updates, percent from top feature and documentation updates
This commit is contained in:
Gert Wohlgemuth 2018-06-20 01:06:56 -07:00 committed by GitHub
commit c7a72d470c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 179 additions and 97 deletions

View File

@ -35,12 +35,12 @@ hesitate to read the source code and understand the mechanism of this bot.
## Table of Contents ## Table of Contents
- [Features](#features) - [Features](#features)
- [Quick start](#quick-start) - [Quick start](#quick-start)
- [Documentations](https://github.com/freqtrade/freqtrade/blob/develop/docs/index.md) - [Documentations](docs/index.md)
- [Installation](https://github.com/freqtrade/freqtrade/blob/develop/docs/installation.md) - [Installation](docs/installation.md)
- [Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md) - [Configuration](docs/configuration.md)
- [Strategy Optimization](https://github.com/freqtrade/freqtrade/blob/develop/docs/bot-optimization.md) - [Strategy Optimization](docs/bot-optimization.md)
- [Backtesting](https://github.com/freqtrade/freqtrade/blob/develop/docs/backtesting.md) - [Backtesting](docs/backtesting.md)
- [Hyperopt](https://github.com/freqtrade/freqtrade/blob/develop/docs/hyperopt.md) - [Hyperopt](docs/hyperopt.md)
- [Support](#support) - [Support](#support)
- [Help](#help--slack) - [Help](#help--slack)
- [Bugs](#bugs--issues) - [Bugs](#bugs--issues)
@ -85,6 +85,10 @@ strategy parameters with real exchange data.
- [x] more indicators - [x] more indicators
- [x] more telegram features - [x] more telegram features
- [x] advanced plotting - [x] advanced plotting
- [x] [using book orders for buy and/or sell](docs/configuration.md)
- [x] [separated unfilled orders timeout](docs/configuration.md)
- [x] [option to disable buying](docs/configuration.md)
- [x] [option to get a buy price based on %](docs/configuration.md)
### Drawbacks ### Drawbacks
@ -100,7 +104,7 @@ strategy parameters with real exchange data.
## Quick start ## Quick start
This quick start section is a very short explanation on how to test the This quick start section is a very short explanation on how to test the
bot in dry-run. We invite you to read the bot in dry-run. We invite you to read the
[bot documentation](https://github.com/freqtrade/freqtrade/blob/develop/docs/index.md) [bot documentation](docs/index.md)
to ensure you understand how the bot is working. to ensure you understand how the bot is working.
### Easy installation ### Easy installation
@ -136,26 +140,26 @@ 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](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](issues?q=is%3Aissue)
first. If it hasn't been reported, please first. If it hasn't been reported, please
[create a new issue](https://github.com/freqtrade/freqtrade/issues/new) and [create a new issue](issues/new) and
ensure you follow the template guide so that our team can assist you as 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](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](labels/enhancement).
If it hasn't been requested, please If it hasn't been requested, please
[create a new request](https://github.com/freqtrade/freqtrade/issues/new) [create a new request](issues/new)
and ensure you follow the template guide so that it does not get lost 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](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](develop/CONTRIBUTING.md)
to understand the requirements before sending your pull-requests. to understand the requirements before sending your pull-requests.
**Important:** Always create your PR against the `develop` branch, not **Important:** Always create your PR against the `develop` branch, not
@ -198,14 +202,14 @@ optional arguments:
only if dry_run is enabled. only if dry_run is enabled.
``` ```
More details on: More details on:
- [How to run the bot](https://github.com/freqtrade/freqtrade/blob/develop/docs/bot-usage.md#bot-commands) - [How to run the bot](docs/bot-usage.md#bot-commands)
- [How to use Backtesting](https://github.com/freqtrade/freqtrade/blob/develop/docs/bot-usage.md#backtesting-commands) - [How to use Backtesting](docs/bot-usage.md#backtesting-commands)
- [How to use Hyperopt](https://github.com/freqtrade/freqtrade/blob/develop/docs/bot-usage.md#hyperopt-commands) - [How to use Hyperopt](docs/bot-usage.md#hyperopt-commands)
### Telegram RPC commands ### Telegram RPC commands
Telegram is not mandatory. However, this is a great way to control your Telegram is not mandatory. However, this is a great way to control your
bot. More details on our bot. More details on our
[documentation](https://github.com/freqtrade/freqtrade/blob/develop/docs/index.md) [documentation](develop/docs/index.md)
- `/start`: Starts the trader - `/start`: Starts the trader
- `/stop`: Stops the trader - `/stop`: Stops the trader

View File

@ -17,7 +17,8 @@
"bid_strategy": { "bid_strategy": {
"ask_last_balance": 0.0, "ask_last_balance": 0.0,
"use_book_order": true, "use_book_order": true,
"book_order_top": 6 "book_order_top": 6,
"percent_from_top": 0.005
}, },
"ask_strategy":{ "ask_strategy":{
"use_book_order": true, "use_book_order": true,
@ -46,7 +47,8 @@
}, },
"experimental": { "experimental": {
"use_sell_signal": false, "use_sell_signal": false,
"sell_profit_only": false "sell_profit_only": false,
"sell_fullfilled_at_roi": false
}, },
"telegram": { "telegram": {
"enabled": true, "enabled": true,

View File

@ -21,7 +21,8 @@
"bid_strategy": { "bid_strategy": {
"ask_last_balance": 0.0, "ask_last_balance": 0.0,
"use_book_order": true, "use_book_order": true,
"book_order_top": 6 "book_order_top": 6,
"percent_from_top": 0.005
}, },
"ask_strategy":{ "ask_strategy":{
"use_book_order": true, "use_book_order": true,
@ -50,7 +51,8 @@
}, },
"experimental": { "experimental": {
"use_sell_signal": false, "use_sell_signal": false,
"sell_profit_only": false "sell_profit_only": false,
"sell_fullfilled_at_roi": false
}, },
"telegram": { "telegram": {
"enabled": true, "enabled": true,

View File

@ -18,12 +18,20 @@ The table below will list all configuration parameters.
| `stake_currency` | BTC | Yes | Crypto-currency used for trading. | `stake_currency` | BTC | Yes | Crypto-currency used for trading.
| `stake_amount` | 0.05 | Yes | Amount of crypto-currency your bot will use for each trade. Per default, the bot will use (0.05 BTC x 3) = 0.15 BTC in total will be always engaged. | `stake_amount` | 0.05 | Yes | Amount of crypto-currency your bot will use for each trade. Per default, the bot will use (0.05 BTC x 3) = 0.15 BTC in total will be always engaged.
| `ticker_interval` | [1m, 5m, 30m, 1h, 1d] | No | The ticker interval to use (1min, 5 min, 30 min, 1 hour or 1 day). Default is 5 minutes | `ticker_interval` | [1m, 5m, 30m, 1h, 1d] | No | The ticker interval to use (1min, 5 min, 30 min, 1 hour or 1 day). Default is 5 minutes
| `fiat_display_currency` | USD | Yes | Fiat currency used to show your profits. More information below. | `fiat_display_currency` | USD | Yes | Fiat currency used to show your profits. [More information below](docs/configuration.md#what-are-the-valid-values-for-fiat_display_currency).
| `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. | `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. [More information below](docs/configuration.md#switch-to-dry-run--paper-trading-mode)
| `minimal_roi` | See below | No | Set the threshold in percent the bot will use to sell a trade. More information below. If set, this parameter will override `minimal_roi` from your strategy file. | `minimal_roi` | See below | No | Set the threshold in percent the bot will use to sell a trade. More information below. If set, this parameter will override `minimal_roi` from your strategy file. [More information below](docs/configuration.md#understanding-minimal_roi).
| `stoploss` | -0.10 | No | Value of the stoploss in percent used by the bot. More information below. If set, this parameter will override `stoploss` from your strategy file. | `stoploss` | -0.10 | No | Value of the stoploss in percent used by the bot. More information below. If set, this parameter will override `stoploss` from your strategy file.
| `unfilledtimeout` | 0 | No | How long (in minutes) the bot will wait for an unfilled order to complete, after which the order will be cancelled. | `disable_buy` | false | No | Disables buying of crypto-currency. Bot will continue to sell.
| `bid_strategy.ask_last_balance` | 0.0 | Yes | Set the bidding price. More information below. | `unfilledtimeout.buy` | 10 | Yes | How long (in minutes) the bot will wait for an unfilled buy order to complete, after which the order will be cancelled.
| `unfilledtimeout.sell` | 10 | Yes | How long (in minutes) the bot will wait for an unfilled sell order to complete, after which the order will be cancelled.
| `bid_strategy.ask_last_balance` | 0.0 | Yes | Set the bidding price. [More information below](docs/configuration.md#understanding-bid_strategyask_last_balance).
| `bid_strategy.use_book_order` | false | No | Use book order to set the bidding price. [More information below](docs/configuration.md#understanding-bid_strategyuse_book_order).
| `bid_strategy.book_order_top` | 1 | No | Selects the top n bidding price in book order. [More information below](docs/configuration.md#understanding-bid_strategyuse_book_order).
| `bid_strategy.percent_from_top` | 0 | No | Set the percent to deduct from the buy rate from book order (if enabled) or from ask/last price. [More information below](docs/configuration.md#understanding-bid_strategypercent_from_top).
| `ask_strategy.use_book_order` | false | No | Use book order to set the asking price. More information below.
| `ask_strategy.book_order_min` | 1 | No | The minimum index from the top to search for profitable asking price from book order. [More information below](docs/configuration.md#understanding-ask_strategyuse_book_order).
| `ask_strategy.book_order_max` | 1 | No | The maximum index from the top to search for profitable asking price from book order. [More information below](docs/configuration.md#understanding-ask_strategyuse_book_order).
| `exchange.name` | bittrex | Yes | Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). | `exchange.name` | bittrex | Yes | Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename).
| `exchange.key` | key | No | API key to use for the exchange. Only required when you are in production mode. | `exchange.key` | key | No | API key to use for the exchange. Only required when you are in production mode.
| `exchange.secret` | secret | No | API secret to use for the exchange. Only required when you are in production mode. | `exchange.secret` | secret | No | API secret to use for the exchange. Only required when you are in production mode.
@ -31,11 +39,12 @@ The table below will list all configuration parameters.
| `exchange.pair_blacklist` | [] | No | List of currency the bot must avoid. Useful when using `--dynamic-whitelist` param. | `exchange.pair_blacklist` | [] | No | List of currency the bot must avoid. Useful when using `--dynamic-whitelist` param.
| `experimental.use_sell_signal` | false | No | Use your sell strategy in addition of the `minimal_roi`. | `experimental.use_sell_signal` | false | No | Use your sell strategy in addition of the `minimal_roi`.
| `experimental.sell_profit_only` | false | No | waits until you have made a positive profit before taking a sell decision. | `experimental.sell_profit_only` | false | No | waits until you have made a positive profit before taking a sell decision.
| `experimental.sell_fullfilled_at_roi` | false | No | automatically creates a sell order based on `minimal_roi` once a buy order has been fullfilled.
| `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`.
| `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](docs/configuration.md#understanding-initial_state).
| `strategy` | DefaultStrategy | No | Defines Strategy class to use. | `strategy` | DefaultStrategy | No | Defines Strategy class to use.
| `strategy_path` | null | No | Adds an additional strategy lookup path (must be a folder). | `strategy_path` | null | No | Adds an additional strategy lookup path (must be a folder).
| `internals.process_throttle_secs` | 5 | Yes | Set the process throttle. Value in second. | `internals.process_throttle_secs` | 5 | Yes | Set the process throttle. Value in second.
@ -43,7 +52,7 @@ The table below will list all configuration parameters.
The definition of each config parameters is in The definition of each config parameters is in
[misc.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/misc.py#L205). [misc.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/misc.py#L205).
### Understand minimal_roi ### Understanding minimal_roi
`minimal_roi` is a JSON object where the key is a duration `minimal_roi` is a JSON object where the key is a duration
in minutes and the value is the minimum ROI in percent. in minutes and the value is the minimum ROI in percent.
See the example below: See the example below:
@ -56,41 +65,34 @@ See the example below:
}, },
``` ```
Most of the strategy files already include the optimal `minimal_roi` Most of the strategy files already include the optimal `minimal_roi` value. This parameter is optional. If you use it, it will take over the `minimal_roi` value from the strategy file.
value. This parameter is optional. If you use it, it will take over the
`minimal_roi` value from the strategy file.
### Understand stoploss ### Understanding stoploss
`stoploss` is loss in percentage that should trigger a sale. `stoploss` is loss in percentage that should trigger a sale. For example value `-0.10` will cause immediate sell if the
For example value `-0.10` will cause immediate sell if the
profit dips below -10% for a given trade. This parameter is optional. profit dips below -10% for a given trade. This parameter is optional.
Most of the strategy files already include the optimal `stoploss` Most of the strategy files already include the optimal `stoploss` value. This parameter is optional. If you use it, it will take over the `stoploss` value from the strategy file.
value. This parameter is optional. If you use it, it will take over the
`stoploss` value from the strategy file.
### Understand initial_state ### Understanding initial_state
`initial_state` is an optional field that defines the initial application state. `initial_state` is an optional field that defines the initial application state. Possible values are `running` or `stopped`. (default=`running`) If the value is `stopped` the bot has to be started with `/start` first.
Possible values are `running` or `stopped`. (default=`running`)
If the value is `stopped` the bot has to be started with `/start` first.
### Understand process_throttle_secs ### Understanding process_throttle_secs
`process_throttle_secs` is an optional field that defines in seconds how long the bot should wait `process_throttle_secs` is an optional field that defines in seconds how long the bot should wait before asking the strategy if we should buy or a sell an asset. After each wait period, the strategy is asked again for every opened trade wether or not we should sell, and for all the remaining pairs (either the dynamic list of pairs or the static list of pairs) if we should buy.
before asking the strategy if we should buy or a sell an asset. After each wait period, the strategy is asked again for
every opened trade wether or not we should sell, and for all the remaining pairs (either the dynamic list of pairs or
the static list of pairs) if we should buy.
### Understand ask_last_balance ### Understanding bid_strategy.ask_last_balance
`ask_last_balance` sets the bidding price. Value `0.0` will use `ask` price, `1.0` will `ask_last_balance` sets the bidding price. Value `0.0` will use `ask` price, `1.0` will use the `last` price and the values between those interpolate between ask and last price. Using `ask` price will guarantee quick success in bid, but bot will also end up paying more then would probably have been necessary.
use the `last` price and values between those interpolate between ask and last
price. Using `ask` price will guarantee quick success in bid, but bot will also
end up paying more then would probably have been necessary.
### What values for exchange.name? ### Understanding bid_strategy.use_book_order
Freqtrade is based on [CCXT library](https://github.com/ccxt/ccxt) that supports 115 cryptocurrency `bid_strategy.use_book_order` loads the exchange book order and sets the bidding price between `book_order_min` and `book_order_max` value. If the `book_order_top` is set to 3, then the 3rd bidding price from the top of the book order will be selected as the bidding price for the trade.
exchange markets and trading APIs. The complete up-to-date list can be found in the
[CCXT repo homepage](https://github.com/ccxt/ccxt/tree/master/python). However, the bot was tested ### Understanding bid_strategy.percent_from_top
with only Bittrex and Binance. `bid_strategy.percent_from_top` sets the percent to deduct from buy price of the pair. If `bid_strategy.use_book_order` is enabled, the percent value is deducted from the rate of `book_order_top`, otherwise, the percent value is deducted from the value provided by `bid_strategy.ask_last_balance`. Example: If `ask_last_balance` rate is 100 and the `bid_strategy.percent_from_top` is `0.005` or `0.5%`, the bot would buy at the price of `99.5`.
### Understanding ask_strategy.use_book_order
`ask_strategy.use_book_order` loads the exchange book order and sets the askng price based on the `book_order_top` value. If the `book_order_min` is set to 3 and `book_order_max` is set to 10, then the bot will search between top 3rd and 10th asking prices from the top of the book order will be selected as the bidding price for the trade.
### What are the valid values for exchange.name?
Freqtrade is based on [CCXT library](https://github.com/ccxt/ccxt) that supports 115+ cryptocurrency exchange markets and trading APIs. The complete up-to-date list can be found in the [CCXT repo homepage](https://github.com/ccxt/ccxt/tree/master/python). However, the bot was thoroughly tested with only Bittrex and Binance.
The bot was tested with the following exchanges: The bot was tested with the following exchanges:
- [Bittrex](https://bittrex.com/): "bittrex" - [Bittrex](https://bittrex.com/): "bittrex"
@ -98,13 +100,13 @@ The bot was tested with the following exchanges:
Feel free to test other exchanges and submit your PR to improve the bot. Feel free to test other exchanges and submit your PR to improve the bot.
### What values for fiat_display_currency? ### What are the valid values for fiat_display_currency?
`fiat_display_currency` set the base currency to use for the conversion from coin to fiat in Telegram. `fiat_display_currency` set the base currency to use for the conversion from coin to fiat in Telegram.
The valid values are: "AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN", "RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", "USD". The valid values are: "AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN", "RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", "USD".
In addition to central bank currencies, a range of cryto currencies are supported. In addition to central bank currencies, a range of cryto currencies are supported.
The valid values are: "BTC", "ETH", "XRP", "LTC", "BCH", "USDT". The valid values are: "BTC", "ETH", "XRP", "LTC", "BCH", "USDT".
## Switch to dry-run mode ## Switch to dry-run / paper trading mode
We recommend starting the bot in dry-run mode to see how your bot will We recommend starting the bot in dry-run mode to see how your bot will
behave and how is the performance of your strategy. In Dry-run mode the behave and how is the performance of your strategy. In Dry-run mode the
bot does not engage your money. It only runs a live simulation without bot does not engage your money. It only runs a live simulation without
@ -131,7 +133,7 @@ creating trades.
Once you will be happy with your bot performance, you can switch it to Once you will be happy with your bot performance, you can switch it to
production mode. production mode.
## Switch to production mode ## Switch to production / live mode
In production mode, the bot will engage your money. Be careful a wrong In production mode, the bot will engage your money. Be careful a wrong
strategy can lose all your money. Be aware of what you are doing when strategy can lose all your money. Be aware of what you are doing when
you run it in production mode. you run it in production mode.

View File

@ -10,7 +10,7 @@ import arrow
from pandas import DataFrame, to_datetime from pandas import DataFrame, to_datetime
from freqtrade import constants from freqtrade import constants
from freqtrade.exchange import get_ticker_history from freqtrade.exchange import get_fee, get_ticker_history
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.strategy.resolver import StrategyResolver, IStrategy from freqtrade.strategy.resolver import StrategyResolver, IStrategy
@ -197,7 +197,6 @@ class Analyze(object):
:return True if bot should sell at current rate :return True if bot should sell at current rate
""" """
current_profit = trade.calc_profit_percent(current_rate) current_profit = trade.calc_profit_percent(current_rate)
if trade.stop_loss is None: if trade.stop_loss is None:
# initially adjust the stop loss to the base value # initially adjust the stop loss to the base value
trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss) trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss)
@ -248,3 +247,15 @@ class Analyze(object):
""" """
return {pair: self.populate_indicators(self.parse_ticker_dataframe(pair_data)) return {pair: self.populate_indicators(self.parse_ticker_dataframe(pair_data))
for pair, pair_data in tickerdata.items()} for pair, pair_data in tickerdata.items()}
def trunc_num(self, f, n):
import math
return math.floor(f * 10 ** n) / 10 ** n
def get_roi_rate(self, trade: Trade) -> float:
current_time = datetime.utcnow()
time_diff = (current_time.timestamp() - trade.open_date.timestamp()) / 60
for duration, threshold in self.strategy.minimal_roi.items():
if time_diff > duration:
roi_rate = (trade.open_rate * (1 + threshold)) * (1+(2.1*get_fee(trade.pair)))
return self.trunc_num(roi_rate, 8)

View File

@ -58,10 +58,10 @@ CONF_SCHEMA = {
'unfilledtimeout': { 'unfilledtimeout': {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'use_book_order': {'type': 'boolean'}, 'buy': {'type': 'number', 'minimum': 1},
'buy': {'type': 'number', 'minimum': 3}, 'sell': {'type': 'number', 'minimum': 1}
'sell': {'type': 'number', 'minimum': 10} },
} 'required': ['buy', 'sell']
}, },
'bid_strategy': { 'bid_strategy': {
'type': 'object', 'type': 'object',
@ -73,24 +73,27 @@ CONF_SCHEMA = {
'exclusiveMaximum': False 'exclusiveMaximum': False
}, },
'use_book_order': {'type': 'boolean'}, 'use_book_order': {'type': 'boolean'},
'book_order_top': {'type': 'number', 'maximum': 20, 'minimum': 1} 'book_order_top': {'type': 'number', 'maximum': 20, 'minimum': 1},
'percent_from_top': {'type': 'number', 'minimum': 0}
}, },
'required': ['ask_last_balance'] 'required': ['ask_last_balance', 'use_book_order']
}, },
'ask_strategy': { 'ask_strategy': {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'use_book_order': {'type': 'boolean'}, 'use_book_order': {'type': 'boolean'},
'book_order_min': {'type': 'number', 'minimum': 1}, 'book_order_min': {'type': 'number', 'minimum': 1},
'book_order_max': {'type': 'number', 'minimum': 1} 'book_order_max': {'type': 'number', 'minimum': 1, 'maximum': 50}
} },
'required': ['use_book_order']
}, },
'exchange': {'$ref': '#/definitions/exchange'}, 'exchange': {'$ref': '#/definitions/exchange'},
'experimental': { 'experimental': {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'use_sell_signal': {'type': 'boolean'}, 'use_sell_signal': {'type': 'boolean'},
'sell_profit_only': {'type': 'boolean'} 'sell_profit_only': {'type': 'boolean'},
'sell_fullfilled_at_roi' : {'type': 'boolean'}
} }
}, },
'telegram': { 'telegram': {

View File

@ -242,8 +242,18 @@ def get_balances() -> dict:
@retrier @retrier
def get_order_book(pair: str, limit: Optional[int] = 1000) -> dict: def get_order_book(pair: str, limit: Optional[int] = 100) -> dict:
try: try:
params = {}
# 20180619: bittrex doesnt support limits -.-
# 20180619: binance limit fix.. binance currently has valid range
if _API.name == 'Binance':
limit_range = [5, 10, 20, 50, 100, 500, 1000]
for limitx in limit_range:
if limit < limitx:
limit = limitx
break
return _API.fetch_order_book(pair, limit) return _API.fetch_order_book(pair, limit)
except ccxt.NotSupported as e: except ccxt.NotSupported as e:
raise OperationalException( raise OperationalException(

View File

@ -164,6 +164,7 @@ class FreqtradeBot(object):
if 'unfilledtimeout' in self.config: if 'unfilledtimeout' in self.config:
# Check and handle any timed out open orders # Check and handle any timed out open orders
if not self.config['dry_run']:
self.check_handle_timedout() self.check_handle_timedout()
Trade.session.flush() Trade.session.flush()
@ -243,24 +244,40 @@ class FreqtradeBot(object):
:param ticker: Ticker to use for getting Ask and Last Price :param ticker: Ticker to use for getting Ask and Last Price
:return: float: Price :return: float: Price
""" """
ticker = exchange.get_ticker(pair) ticker = exchange.get_ticker(pair)
logger.info('ticker data %s', ticker)
if ticker['ask'] < ticker['last']: if ticker['ask'] < ticker['last']:
return ticker['ask'] ticker_rate = ticker['ask']
else:
balance = self.config['bid_strategy']['ask_last_balance'] balance = self.config['bid_strategy']['ask_last_balance']
ticker_rate = ticker['ask'] + balance * (ticker['last'] - ticker['ask']) ticker_rate = ticker['ask'] + balance * (ticker['last'] - ticker['ask'])
used_rate = ticker_rate
if self.config['bid_strategy'].get('use_book_order', False): if self.config['bid_strategy'].get('use_book_order', False):
logger.info('Getting price from Order Book') logger.info('Getting price from Order Book')
orderBook = exchange.get_order_book(pair) orderBook_top = self.config.get('bid_strategy',{}).get('book_order_top',1)
orderBook_rate = orderBook['bids'][self.config['bid_strategy']['book_order_top']][0] orderBook = exchange.get_order_book(pair, orderBook_top)
# top 1 = index 0
orderBook_rate = orderBook['bids'][orderBook_top-1][0]
orderBook_rate = orderBook_rate+0.00000001
# if ticker has lower rate, then use ticker ( usefull if down trending ) # if ticker has lower rate, then use ticker ( usefull if down trending )
logger.info('...book order buy rate %0.8f', orderBook_rate)
if ticker_rate < orderBook_rate: if ticker_rate < orderBook_rate:
return ticker_rate logger.info('...using ticker rate instead %0.8f', ticker_rate)
return orderBook_rate used_rate = ticker_rate
used_rate = orderBook_rate
else: else:
logger.info('Using Ask / Last Price') logger.info('Using Last Ask / Last Price')
return ticker_rate used_rate = ticker_rate
percent_from_top = self.config.get('bid_strategy',{}).get('percent_from_top',0)
if percent_from_top > 0:
used_rate = used_rate - (used_rate * percent_from_top)
used_rate = self.analyze.trunc_num(used_rate, 8)
logger.info('...percent_from_top enabled, new buy rate %0.8f', used_rate)
return used_rate
def create_trade(self) -> bool: def create_trade(self) -> bool:
""" """
@ -269,6 +286,7 @@ class FreqtradeBot(object):
:return: True if a trade object has been created and persisted, False otherwise :return: True if a trade object has been created and persisted, False otherwise
""" """
stake_amount = self.config['stake_amount'] stake_amount = self.config['stake_amount']
interval = self.analyze.get_ticker_interval() interval = self.analyze.get_ticker_interval()
stake_currency = self.config['stake_currency'] stake_currency = self.config['stake_currency']
fiat_currency = self.config['fiat_display_currency'] fiat_currency = self.config['fiat_display_currency']
@ -279,8 +297,10 @@ class FreqtradeBot(object):
stake_amount stake_amount
) )
whitelist = copy.deepcopy(self.config['exchange']['pair_whitelist']) whitelist = copy.deepcopy(self.config['exchange']['pair_whitelist'])
# Check if stake_amount is fulfilled # Check if stake_amount is fulfilled
if exchange.get_balance(stake_currency) < stake_amount: current_balance = exchange.get_balance(self.config['stake_currency'])
if current_balance < stake_amount:
raise DependencyException( raise DependencyException(
f'stake amount is not fulfilled (currency={stake_currency})') f'stake amount is not fulfilled (currency={stake_currency})')
@ -436,24 +456,34 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \
if not trade.is_open: if not trade.is_open:
raise ValueError(f'attempt to handle closed trade: {trade}') raise ValueError(f'attempt to handle closed trade: {trade}')
logger.debug('Handling %s ...', trade) logger.info('Handling %s ...', trade)
sell_rate = exchange.get_ticker(trade.pair)['bid'] sell_rate = exchange.get_ticker(trade.pair)['bid']
logger.info(' ticker rate %0.8f', sell_rate)
(buy, sell) = (False, False) (buy, sell) = (False, False)
if self.config.get('experimental', {}).get('use_sell_signal'): if self.config.get('experimental', {}).get('use_sell_signal'):
(buy, sell) = self.analyze.get_signal(trade.pair, self.analyze.get_ticker_interval()) (buy, sell) = self.analyze.get_signal(trade.pair, self.analyze.get_ticker_interval())
is_set_fullfilled_at_roi = self.config.get('experimental', {}).get('sell_fullfilled_at_roi', False)
if is_set_fullfilled_at_roi:
sell_rate = self.analyze.get_roi_rate(trade)
logger.info('trying to selling at roi rate %0.8f', sell_rate)
if 'ask_strategy' in self.config and self.config['ask_strategy'].get('use_book_order', False): if 'ask_strategy' in self.config and self.config['ask_strategy'].get('use_book_order', False):
logger.info('Using order book for selling...') logger.info('Using order book for selling...')
orderBook = exchange.get_order_book(trade.pair)
# logger.debug('Order book %s',orderBook) # logger.debug('Order book %s',orderBook)
orderBook_min = self.config['ask_strategy']['book_order_min'] orderBook_min = self.config['ask_strategy']['book_order_min']
orderBook_max = self.config['ask_strategy']['book_order_max'] orderBook_max = self.config['ask_strategy']['book_order_max']
orderBook = exchange.get_order_book(trade.pair, orderBook_max)
for i in range(orderBook_min, orderBook_max+1): for i in range(orderBook_min, orderBook_max+1):
orderBook_rate = orderBook['asks'][i-1][0] orderBook_rate = orderBook['asks'][i-1][0]
# if orderbook has higher rate (high profit), # if orderbook has higher rate (high profit),
# use orderbook, otherwise just use sell rate # use orderbook, otherwise just use bids rate
logger.info(' order book asks top %s: %0.8f', i, orderBook_rate)
if (sell_rate < orderBook_rate): if (sell_rate < orderBook_rate):
sell_rate = orderBook_rate sell_rate = orderBook_rate
@ -461,6 +491,7 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \
return True return True
break break
else: else:
logger.info('checking sell')
if self.check_sell(trade, sell_rate, buy, sell): if self.check_sell(trade, sell_rate, buy, sell):
return True return True
@ -502,7 +533,7 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \
ordertime = arrow.get(order['datetime']).datetime ordertime = arrow.get(order['datetime']).datetime
# Check if trade is still actually open # Check if trade is still actually open
if order['status'] == 'open': if (order['status'] == 'open'):
if order['side'] == 'buy' and ordertime < buy_timeoutthreashold: if order['side'] == 'buy' and ordertime < buy_timeoutthreashold:
self.handle_timedout_limit_buy(trade, order) self.handle_timedout_limit_buy(trade, order)
elif order['side'] == 'sell' and ordertime < sell_timeoutthreashold: elif order['side'] == 'sell' and ordertime < sell_timeoutthreashold:

View File

@ -180,7 +180,8 @@ class Telegram(RPC):
headers=[ headers=[
'Day', 'Day',
'Profit {}'.format(self._config['stake_currency']), 'Profit {}'.format(self._config['stake_currency']),
'Profit {}'.format(self._config['fiat_display_currency']) 'Profit {}'.format(self._config['fiat_display_currency']),
'Trades'
], ],
tablefmt='simple') tablefmt='simple')
message = '<b>Daily Profit over the last {} days</b>:\n<pre>{}</pre>'\ message = '<b>Daily Profit over the last {} days</b>:\n<pre>{}</pre>'\

View File

@ -98,6 +98,7 @@ def default_conf():
"use_book_order": False, "use_book_order": False,
"book_order_top": 6, "book_order_top": 6,
"ask_last_balance": 0.0, "ask_last_balance": 0.0,
"percent_from_top": 0.0
}, },
"ask_strategy": { "ask_strategy": {
"use_book_order": False, "use_book_order": False,

View File

@ -499,7 +499,12 @@ def test_balance_fully_ask_side(mocker) -> None:
""" """
Test get_target_bid() method Test get_target_bid() method
""" """
param = {'use_book_order': False, 'book_order_top': 6, 'ask_last_balance': 0.0} param = {
'use_book_order': False,
'book_order_top': 6,
'ask_last_balance': 0.0,
'percent_from_top': 0
}
freqtrade = get_patched_freqtradebot(mocker, {'bid_strategy': param}) freqtrade = get_patched_freqtradebot(mocker, {'bid_strategy': param})
assert freqtrade.get_target_bid('ETH/BTC') >= 0.07 assert freqtrade.get_target_bid('ETH/BTC') >= 0.07
@ -509,7 +514,12 @@ def test_balance_fully_last_side(mocker) -> None:
""" """
Test get_target_bid() method Test get_target_bid() method
""" """
param = {'use_book_order': False, 'book_order_top': 6, 'ask_last_balance': 0.0} param = {
'use_book_order': False,
'book_order_top': 6,
'ask_last_balance': 0.0,
'percent_from_top': 0
}
freqtrade = get_patched_freqtradebot(mocker, {'bid_strategy': param}) freqtrade = get_patched_freqtradebot(mocker, {'bid_strategy': param})
assert freqtrade.get_target_bid('ETH/BTC') >= 0.07 assert freqtrade.get_target_bid('ETH/BTC') >= 0.07
@ -519,7 +529,12 @@ def test_balance_bigger_last_ask(mocker) -> None:
""" """
Test get_target_bid() method Test get_target_bid() method
""" """
param = {'use_book_order': False, 'book_order_top': 6, 'ask_last_balance': 0.0} param = {
'use_book_order': False,
'book_order_top': 6,
'ask_last_balance': 0.0,
'percent_from_top': 0.00
}
freqtrade = get_patched_freqtradebot(mocker, {'bid_strategy': param}) freqtrade = get_patched_freqtradebot(mocker, {'bid_strategy': param})
assert freqtrade.get_target_bid('ETH/BTC') >= 0.07 assert freqtrade.get_target_bid('ETH/BTC') >= 0.07