mirror of
https://github.com/freqtrade/freqtrade.git
synced 2025-11-29 08:33:07 +00:00
@@ -89,7 +89,6 @@
|
|||||||
],
|
],
|
||||||
"exchange": {
|
"exchange": {
|
||||||
"name": "binance",
|
"name": "binance",
|
||||||
"sandbox": false,
|
|
||||||
"key": "your_exchange_key",
|
"key": "your_exchange_key",
|
||||||
"secret": "your_exchange_secret",
|
"secret": "your_exchange_secret",
|
||||||
"password": "",
|
"password": "",
|
||||||
|
|||||||
@@ -188,7 +188,6 @@ Mandatory parameters are marked as **Required**, which means that they are requi
|
|||||||
| `max_entry_position_adjustment` | Maximum additional order(s) for each open trade on top of the first entry Order. Set it to `-1` for unlimited additional orders. [More information here](strategy-callbacks.md#adjust-trade-position). <br> [Strategy Override](#parameters-in-the-strategy). <br>*Defaults to `-1`.*<br> **Datatype:** Positive Integer or -1
|
| `max_entry_position_adjustment` | Maximum additional order(s) for each open trade on top of the first entry Order. Set it to `-1` for unlimited additional orders. [More information here](strategy-callbacks.md#adjust-trade-position). <br> [Strategy Override](#parameters-in-the-strategy). <br>*Defaults to `-1`.*<br> **Datatype:** Positive Integer or -1
|
||||||
| | **Exchange**
|
| | **Exchange**
|
||||||
| `exchange.name` | **Required.** Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). <br> **Datatype:** String
|
| `exchange.name` | **Required.** Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). <br> **Datatype:** String
|
||||||
| `exchange.sandbox` | Use the 'sandbox' version of the exchange, where the exchange provides a sandbox for risk-free integration. See [here](sandbox-testing.md) in more details.<br> **Datatype:** Boolean
|
|
||||||
| `exchange.key` | API key to use for the exchange. Only required when you are in production mode.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String
|
| `exchange.key` | API key to use for the exchange. Only required when you are in production mode.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String
|
||||||
| `exchange.secret` | API secret to use for the exchange. Only required when you are in production mode.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String
|
| `exchange.secret` | API secret to use for the exchange. Only required when you are in production mode.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String
|
||||||
| `exchange.password` | API password to use for the exchange. Only required when you are in production mode and for exchanges that use password for API requests.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String
|
| `exchange.password` | API password to use for the exchange. Only required when you are in production mode and for exchanges that use password for API requests.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
# Sandbox API testing
|
|
||||||
|
|
||||||
Some exchanges provide sandboxes or testbeds for risk-free testing, while running the bot against a real exchange.
|
|
||||||
With some configuration, freqtrade (in combination with ccxt) provides access to these.
|
|
||||||
|
|
||||||
This document is an overview to configure Freqtrade to be used with sandboxes.
|
|
||||||
This can be useful to developers and trader alike.
|
|
||||||
|
|
||||||
!!! Warning
|
|
||||||
Sandboxes usually have very low volume, and either a very wide spread, or no orders available at all.
|
|
||||||
Therefore, sandboxes will usually not do a good job of showing you how a strategy would work in real trading.
|
|
||||||
|
|
||||||
## Exchanges known to have a sandbox / testnet
|
|
||||||
|
|
||||||
* [binance](https://testnet.binance.vision/)
|
|
||||||
* [coinbasepro](https://public.sandbox.pro.coinbase.com)
|
|
||||||
* [gemini](https://exchange.sandbox.gemini.com/)
|
|
||||||
* [huobipro](https://www.testnet.huobi.pro/)
|
|
||||||
* [kucoin](https://sandbox.kucoin.com/)
|
|
||||||
* [phemex](https://testnet.phemex.com/)
|
|
||||||
|
|
||||||
!!! Note
|
|
||||||
We did not test correct functioning of all of the above testnets. Please report your experiences with each sandbox.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Configure a Sandbox account
|
|
||||||
|
|
||||||
When testing your API connectivity, make sure to use the appropriate sandbox / testnet URL.
|
|
||||||
|
|
||||||
In general, you should follow these steps to enable an exchange's sandbox:
|
|
||||||
|
|
||||||
* Figure out if an exchange has a sandbox (most likely by using google or the exchange's support documents)
|
|
||||||
* Create a sandbox account (often the sandbox-account requires separate registration)
|
|
||||||
* [Add some test assets to account](#add-test-funds)
|
|
||||||
* Create API keys
|
|
||||||
|
|
||||||
### Add test funds
|
|
||||||
|
|
||||||
Usually, sandbox exchanges allow depositing funds directly via web-interface.
|
|
||||||
You should make sure to have a realistic amount of funds available to your test-account, so results are representable of your real account funds.
|
|
||||||
|
|
||||||
!!! Warning
|
|
||||||
Test exchanges will **NEVER** require your real credit card or banking details!
|
|
||||||
|
|
||||||
## Configure freqtrade to use a exchange's sandbox
|
|
||||||
|
|
||||||
### Sandbox URLs
|
|
||||||
|
|
||||||
Freqtrade makes use of CCXT which in turn provides a list of URLs to Freqtrade.
|
|
||||||
These include `['test']` and `['api']`.
|
|
||||||
|
|
||||||
* `[Test]` if available will point to an Exchanges sandbox.
|
|
||||||
* `[Api]` normally used, and resolves to live API target on the exchange.
|
|
||||||
|
|
||||||
To make use of sandbox / test add "sandbox": true, to your config.json
|
|
||||||
|
|
||||||
```json
|
|
||||||
"exchange": {
|
|
||||||
"name": "coinbasepro",
|
|
||||||
"sandbox": true,
|
|
||||||
"key": "5wowfxemogxeowo;heiohgmd",
|
|
||||||
"secret": "/ZMH1P62rCVmwefewrgcewX8nh4gob+lywxfwfxwwfxwfNsH1ySgvWCUR/w==",
|
|
||||||
"password": "1bkjfkhfhfu6sr",
|
|
||||||
"outdated_offset": 5
|
|
||||||
"pair_whitelist": [
|
|
||||||
"BTC/USD"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"datadir": "user_data/data/coinbasepro_sandbox"
|
|
||||||
```
|
|
||||||
|
|
||||||
Also the following information:
|
|
||||||
|
|
||||||
* api-key (created for the sandbox webpage)
|
|
||||||
* api-secret (noted earlier)
|
|
||||||
* password (the passphrase - noted earlier)
|
|
||||||
|
|
||||||
!!! Tip "Different data directory"
|
|
||||||
We also recommend to set `datadir` to something identifying downloaded data as sandbox data, to avoid having sandbox data mixed with data from the real exchange.
|
|
||||||
This can be done by adding the `"datadir"` key to the configuration.
|
|
||||||
Now, whenever you use this configuration, your data directory will be set to this directory.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## You should now be ready to test your sandbox
|
|
||||||
|
|
||||||
Ensure Freqtrade logs show the sandbox URL, and trades made are shown in sandbox. Also make sure to select a pair which shows at least some decent value (which very often is BTC/<somestablecoin>).
|
|
||||||
|
|
||||||
## Common problems with sandbox exchanges
|
|
||||||
|
|
||||||
Sandbox exchange instances often have very low volume, which can cause some problems which usually are not seen on a real exchange instance.
|
|
||||||
|
|
||||||
### Old Candles problem
|
|
||||||
|
|
||||||
Since Sandboxes often have low volume, candles can be quite old and show no volume.
|
|
||||||
To disable the error "Outdated history for pair ...", best increase the parameter `"outdated_offset"` to a number that seems realistic for the sandbox you're using.
|
|
||||||
|
|
||||||
### Unfilled orders
|
|
||||||
|
|
||||||
Sandboxes often have very low volumes - which means that many trades can go unfilled, or can go unfilled for a very long time.
|
|
||||||
|
|
||||||
To mitigate this, you can try to match the first order on the opposite orderbook side using the following configuration:
|
|
||||||
|
|
||||||
``` jsonc
|
|
||||||
"order_types": {
|
|
||||||
"entry": "limit",
|
|
||||||
"exit": "limit"
|
|
||||||
// ...
|
|
||||||
},
|
|
||||||
"entry_pricing": {
|
|
||||||
"price_side": "other",
|
|
||||||
// ...
|
|
||||||
},
|
|
||||||
"exit_pricing":{
|
|
||||||
"price_side": "other",
|
|
||||||
// ...
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
The configuration is similar to the suggested configuration for market orders - however by using limit-orders you can avoid moving the price too much, and you can set the worst price you might get.
|
|
||||||
@@ -461,7 +461,6 @@ CONF_SCHEMA = {
|
|||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
'name': {'type': 'string'},
|
'name': {'type': 'string'},
|
||||||
'sandbox': {'type': 'boolean', 'default': False},
|
|
||||||
'key': {'type': 'string', 'default': ''},
|
'key': {'type': 'string', 'default': ''},
|
||||||
'secret': {'type': 'string', 'default': ''},
|
'secret': {'type': 'string', 'default': ''},
|
||||||
'password': {'type': 'string', 'default': ''},
|
'password': {'type': 'string', 'default': ''},
|
||||||
|
|||||||
@@ -263,8 +263,6 @@ class Exchange:
|
|||||||
except ccxt.BaseError as e:
|
except ccxt.BaseError as e:
|
||||||
raise OperationalException(f"Initialization of ccxt failed. Reason: {e}") from e
|
raise OperationalException(f"Initialization of ccxt failed. Reason: {e}") from e
|
||||||
|
|
||||||
self.set_sandbox(api, exchange_config, name)
|
|
||||||
|
|
||||||
return api
|
return api
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -465,16 +463,6 @@ class Exchange:
|
|||||||
return amount_to_contract_precision(amount, self.get_precision_amount(pair),
|
return amount_to_contract_precision(amount, self.get_precision_amount(pair),
|
||||||
self.precisionMode, contract_size)
|
self.precisionMode, contract_size)
|
||||||
|
|
||||||
def set_sandbox(self, api: ccxt.Exchange, exchange_config: dict, name: str) -> None:
|
|
||||||
if exchange_config.get('sandbox'):
|
|
||||||
if api.urls.get('test'):
|
|
||||||
api.urls['api'] = api.urls['test']
|
|
||||||
logger.info("Enabled Sandbox API on %s", name)
|
|
||||||
else:
|
|
||||||
logger.warning(
|
|
||||||
f"No Sandbox URL in CCXT for {name}, exiting. Please check your config.json")
|
|
||||||
raise OperationalException(f'Exchange {name} does not provide a sandbox api')
|
|
||||||
|
|
||||||
def _load_async_markets(self, reload: bool = False) -> None:
|
def _load_async_markets(self, reload: bool = False) -> None:
|
||||||
try:
|
try:
|
||||||
if self._api_async:
|
if self._api_async:
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ nav:
|
|||||||
- Advanced Hyperopt: advanced-hyperopt.md
|
- Advanced Hyperopt: advanced-hyperopt.md
|
||||||
- Producer/Consumer mode: producer-consumer.md
|
- Producer/Consumer mode: producer-consumer.md
|
||||||
- Edge Positioning: edge.md
|
- Edge Positioning: edge.md
|
||||||
- Sandbox Testing: sandbox-testing.md
|
|
||||||
- FAQ: faq.md
|
- FAQ: faq.md
|
||||||
- SQL Cheat-sheet: sql_cheatsheet.md
|
- SQL Cheat-sheet: sql_cheatsheet.md
|
||||||
- Strategy migration: strategy_migration.md
|
- Strategy migration: strategy_migration.md
|
||||||
|
|||||||
@@ -556,41 +556,6 @@ def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
|
|||||||
assert result == 4000
|
assert result == 4000
|
||||||
|
|
||||||
|
|
||||||
def test_set_sandbox(default_conf, mocker):
|
|
||||||
"""
|
|
||||||
Test working scenario
|
|
||||||
"""
|
|
||||||
api_mock = MagicMock()
|
|
||||||
api_mock.load_markets = MagicMock(return_value={
|
|
||||||
'ETH/BTC': '', 'LTC/BTC': '', 'XRP/BTC': '', 'NEO/BTC': ''
|
|
||||||
})
|
|
||||||
url_mock = PropertyMock(return_value={'test': "api-public.sandbox.gdax.com",
|
|
||||||
'api': 'https://api.gdax.com'})
|
|
||||||
type(api_mock).urls = url_mock
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
||||||
liveurl = exchange._api.urls['api']
|
|
||||||
default_conf['exchange']['sandbox'] = True
|
|
||||||
exchange.set_sandbox(exchange._api, default_conf['exchange'], 'Logname')
|
|
||||||
assert exchange._api.urls['api'] != liveurl
|
|
||||||
|
|
||||||
|
|
||||||
def test_set_sandbox_exception(default_conf, mocker):
|
|
||||||
"""
|
|
||||||
Test Fail scenario
|
|
||||||
"""
|
|
||||||
api_mock = MagicMock()
|
|
||||||
api_mock.load_markets = MagicMock(return_value={
|
|
||||||
'ETH/BTC': '', 'LTC/BTC': '', 'XRP/BTC': '', 'NEO/BTC': ''
|
|
||||||
})
|
|
||||||
url_mock = PropertyMock(return_value={'api': 'https://api.gdax.com'})
|
|
||||||
type(api_mock).urls = url_mock
|
|
||||||
|
|
||||||
with pytest.raises(OperationalException, match=r'does not provide a sandbox api'):
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
|
||||||
default_conf['exchange']['sandbox'] = True
|
|
||||||
exchange.set_sandbox(exchange._api, default_conf['exchange'], 'Logname')
|
|
||||||
|
|
||||||
|
|
||||||
def test__load_async_markets(default_conf, mocker, caplog):
|
def test__load_async_markets(default_conf, mocker, caplog):
|
||||||
mocker.patch(f'{EXMS}._init_ccxt')
|
mocker.patch(f'{EXMS}._init_ccxt')
|
||||||
mocker.patch(f'{EXMS}.validate_pairs')
|
mocker.patch(f'{EXMS}.validate_pairs')
|
||||||
|
|||||||
@@ -1038,8 +1038,7 @@ def test_load_config_stoploss_exchange_limit_ratio(all_conf) -> None:
|
|||||||
validate_config_schema(all_conf)
|
validate_config_schema(all_conf)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("keys", [("exchange", "sandbox", False),
|
@pytest.mark.parametrize("keys", [("exchange", "key", ""),
|
||||||
("exchange", "key", ""),
|
|
||||||
("exchange", "secret", ""),
|
("exchange", "secret", ""),
|
||||||
("exchange", "password", ""),
|
("exchange", "password", ""),
|
||||||
])
|
])
|
||||||
|
|||||||
Reference in New Issue
Block a user