Logging to file implemented. Still missing trades CSV.
Some checks failed
Test Python / Test (push) Failing after 24s
Some checks failed
Test Python / Test (push) Failing after 24s
This commit is contained in:
parent
113f1ca158
commit
59cda73349
|
@ -1,18 +1,84 @@
|
||||||
"""# Automatic Crypto Seller.
|
"""# Automatic Crypto Seller.
|
||||||
|
|
||||||
Description TODO.
|
This is a system for automatically trading individual financial assets a single
|
||||||
|
way, by using repeated trades over a period.
|
||||||
|
|
||||||
|
The primary motivation is for trading low-volume crypto assets without
|
||||||
|
affecting the price too much.
|
||||||
|
|
||||||
|
Supported sites:
|
||||||
|
|
||||||
|
- [KuCoin](https://www.kucoin.com/): Online crypto-currency exchange.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Install dependencies:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Configure the sell rate:
|
||||||
|
|
||||||
|
Todo:
|
||||||
|
----
|
||||||
|
Run using from the top directory:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
python -m crypto_seller
|
||||||
|
```
|
||||||
|
|
||||||
|
The script will now automatically sell assets over time. The interval between
|
||||||
|
sell-offs are randomized to avoid front-running, and the amounts are also
|
||||||
|
randomized to avoid too consistent behaviour.
|
||||||
|
|
||||||
|
The log will both be displayed in the shell, and be placed in a log file
|
||||||
|
`output/log.txt`. Every sell-off will be logged to the `output/trades.csv`
|
||||||
|
file, with as much information as possible. Keep both of these for tax
|
||||||
|
purposes, if relevant.
|
||||||
|
|
||||||
|
Todo:
|
||||||
|
----
|
||||||
|
## Auditing information
|
||||||
|
|
||||||
|
The most relevant libraries for auditing are:
|
||||||
|
|
||||||
|
- [`fin_depo`](https://gitfub.space/Jmaa/fin-depo): Library for programmatic
|
||||||
|
fetching of depository assets and in some cases allows for order placement.
|
||||||
|
This is the library that reads balances and places market orders.
|
||||||
|
- [`fin_defs`](https://gitfub.space/Jmaa/fin-defs): Definitions of financial
|
||||||
|
assets and instruments. Used by `fin_depo`.
|
||||||
|
- [`python-kucoin`](https://python-kucoin.readthedocs.io/en/latest/) is used by
|
||||||
|
`fin_depo` for providing KuCoin support.
|
||||||
|
|
||||||
|
Todo
|
||||||
|
|
||||||
|
## Taxation
|
||||||
|
|
||||||
|
Some parts of the world suffers from weird and draconian taxation rules on
|
||||||
|
cryptocurrencies, so it helps to keep track of the relevant trading
|
||||||
|
information.
|
||||||
|
|
||||||
|
As mentioned above, keep (and backup) both the log file (`output/log.txt`) and
|
||||||
|
the trades file (`output/trades.csv`).
|
||||||
|
|
||||||
|
To help with tax reporting, it might be useful to sign up to tax oriented
|
||||||
|
websites. For example, [CryptoSkat](https://cryptoskat.dk/) seems to be the
|
||||||
|
most mature on the danish market, and does support KuCoin.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__all__ = ['__version__', 'run_auto_sell']
|
__all__ = ['__version__', 'run_auto_sell']
|
||||||
|
|
||||||
import datetime
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import random
|
import datetime
|
||||||
from typing import Any
|
|
||||||
import logging
|
import logging
|
||||||
from decimal import Decimal
|
import random
|
||||||
import time
|
import time
|
||||||
|
from decimal import Decimal
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import fin_defs
|
import fin_defs
|
||||||
import fin_depo
|
import fin_depo
|
||||||
|
@ -21,7 +87,17 @@ from . import config
|
||||||
from ._version import __version__
|
from ._version import __version__
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.setLevel('INFO')
|
|
||||||
|
################################################################################
|
||||||
|
# Constants #
|
||||||
|
|
||||||
|
PATH_OUTPUT = Path('./output').absolute()
|
||||||
|
PATH_LOG_FILE = PATH_OUTPUT / 'log.txt'
|
||||||
|
PATH_TRADES_FILE = PATH_OUTPUT / 'trades.csv'
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Main code #
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class AutoSellConfig:
|
class AutoSellConfig:
|
||||||
|
@ -31,35 +107,41 @@ class AutoSellConfig:
|
||||||
output_asset: fin_defs.Asset
|
output_asset: fin_defs.Asset
|
||||||
exit_when_empty: bool = True
|
exit_when_empty: bool = True
|
||||||
|
|
||||||
|
|
||||||
def sample_from_range(rng: random.Random, range: tuple[Any, Any]) -> Any:
|
def sample_from_range(rng: random.Random, range: tuple[Any, Any]) -> Any:
|
||||||
multiplier = rng.random()
|
multiplier = rng.random()
|
||||||
if isinstance(range[0], Decimal):
|
if isinstance(range[0], Decimal):
|
||||||
multiplier = Decimal(multiplier)
|
multiplier = Decimal(multiplier)
|
||||||
return range[0] + (range[1] - range[0]) * multiplier
|
return range[0] + (range[1] - range[0]) * multiplier
|
||||||
|
|
||||||
|
|
||||||
SELLER = fin_depo.defi_kucoin.KucoinDepoFetcher(
|
SELLER = fin_depo.defi_kucoin.KucoinDepoFetcher(
|
||||||
kucoin_secret = config.KUCOIN_SECRET,
|
kucoin_secret=config.KUCOIN_SECRET,
|
||||||
kucoin_key = config.KUCOIN_KEY,
|
kucoin_key=config.KUCOIN_KEY,
|
||||||
kucoin_pass = config.KUCOIN_PASS,
|
kucoin_pass=config.KUCOIN_PASS,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def determine_available_tokens(token: fin_defs.Asset) -> Decimal:
|
def determine_available_tokens(token: fin_defs.Asset) -> Decimal:
|
||||||
return SELLER.get_depo().get_amount_of_asset(token)
|
return SELLER.get_depo().get_amount_of_asset(token)
|
||||||
|
|
||||||
def sell_tokens(input_asset: fin_defs.Asset, input_amount: Decimal,
|
|
||||||
output_asset: fin_defs.Asset) -> fin_depo.data.TradeOrderDetails:
|
def sell_tokens(
|
||||||
#return SELLER.place_market_order(input_asset, input_amount, output_asset)
|
input_asset: fin_defs.Asset, input_amount: Decimal, output_asset: fin_defs.Asset,
|
||||||
|
) -> fin_depo.data.TradeOrderDetails:
|
||||||
|
# return SELLER.place_market_order(input_asset, input_amount, output_asset)
|
||||||
return fin_depo.data.TradeOrderDetails(
|
return fin_depo.data.TradeOrderDetails(
|
||||||
input_asset= input_asset,
|
input_asset=input_asset,
|
||||||
input_amount= input_amount,
|
input_amount=input_amount,
|
||||||
output_asset= output_asset,
|
output_asset=output_asset,
|
||||||
output_amount= input_amount,
|
output_amount=input_amount,
|
||||||
fee_asset = input_asset,
|
fee_asset=input_asset,
|
||||||
fee_amount = input_amount,
|
fee_amount=input_amount,
|
||||||
order_id = 10001,
|
order_id=10001,
|
||||||
raw_order_details = {'TEST': 1, 'DATA': 2},
|
raw_order_details={'TEST': 1, 'DATA': 2},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def run_auto_sell(config: AutoSellConfig):
|
def run_auto_sell(config: AutoSellConfig):
|
||||||
rng = random.SystemRandom()
|
rng = random.SystemRandom()
|
||||||
|
|
||||||
|
@ -73,7 +155,9 @@ def run_auto_sell(config: AutoSellConfig):
|
||||||
amount_to_sell = min(input_amount_available, amount_to_sell)
|
amount_to_sell = min(input_amount_available, amount_to_sell)
|
||||||
logger.info('Attempting to sell %s %s', amount_to_sell, config.input_asset)
|
logger.info('Attempting to sell %s %s', amount_to_sell, config.input_asset)
|
||||||
|
|
||||||
order_details = sell_tokens(config.input_asset, amount_to_sell, config.output_asset)
|
order_details = sell_tokens(
|
||||||
|
config.input_asset, amount_to_sell, config.output_asset,
|
||||||
|
)
|
||||||
print(order_details)
|
print(order_details)
|
||||||
# TODO: Write order details to file.
|
# TODO: Write order details to file.
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,41 @@
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
|
import logging.handlers
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import fin_defs
|
import fin_defs
|
||||||
|
|
||||||
from . import run_auto_sell, AutoSellConfig
|
from . import PATH_LOG_FILE, AutoSellConfig, run_auto_sell
|
||||||
|
from . import logger as module_logger
|
||||||
logging.basicConfig()
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.setLevel('INFO')
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
PATH_LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
file_handler = logging.handlers.WatchedFileHandler(filename=PATH_LOG_FILE)
|
||||||
|
file_handler.setFormatter(
|
||||||
|
logging.Formatter(
|
||||||
|
'%(levelname)s:%(asctime)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.basicConfig(handlers=[logging.StreamHandler(), file_handler])
|
||||||
|
|
||||||
|
logger.setLevel('INFO')
|
||||||
|
module_logger.setLevel('INFO')
|
||||||
|
|
||||||
logger.info('Initializing crypto_seller')
|
logger.info('Initializing crypto_seller')
|
||||||
|
|
||||||
config = AutoSellConfig(
|
config = AutoSellConfig(
|
||||||
input_amount_range= (Decimal('0.5'), Decimal('1')),
|
input_amount_range=(Decimal('0.5'), Decimal('1')),
|
||||||
interval_range= (datetime.timedelta(seconds=2),
|
interval_range=(datetime.timedelta(seconds=2), datetime.timedelta(seconds=6)),
|
||||||
datetime.timedelta(seconds=6)),
|
input_asset=fin_defs.MPC,
|
||||||
input_asset = fin_defs.MPC,
|
output_asset=fin_defs.USDT,
|
||||||
output_asset = fin_defs.USDT,
|
exit_when_empty=True,
|
||||||
exit_when_empty = True,
|
|
||||||
)
|
)
|
||||||
run_auto_sell(config)
|
run_auto_sell(config)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user