1
0

Present some starts on completion.

This commit is contained in:
Jon Michael Aanes 2024-07-22 14:12:05 +02:00
parent bb2ac019ab
commit af48230498
3 changed files with 64 additions and 12 deletions

View File

@ -20,10 +20,6 @@ pip install -r requirements.txt
## Usage ## Usage
Configure the sell rate:
TODO
Run using from the top directory: Run using from the top directory:
```shell ```shell
@ -51,8 +47,6 @@ The most relevant libraries for auditing are:
- [`python-kucoin`](https://python-kucoin.readthedocs.io/en/latest/) is used by - [`python-kucoin`](https://python-kucoin.readthedocs.io/en/latest/) is used by
`fin_depo` for providing KuCoin support. `fin_depo` for providing KuCoin support.
TODO
## Taxation ## Taxation
Some parts of the world suffers from weird and draconian taxation rules on Some parts of the world suffers from weird and draconian taxation rules on
@ -66,6 +60,14 @@ 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 websites. For example, [CryptoSkat](https://cryptoskat.dk/) seems to be the
most mature on the danish market, and does support KuCoin. most mature on the danish market, and does support KuCoin.
## TODO
- [ ] Log all trades to CSV file.
- [ ] Parse configuration from json.
- [X] Collect information during the run and output after run
- [ ] Document configuration
- [ ] Document auditing
""" """
__all__ = ['__version__', 'run_auto_sell'] __all__ = ['__version__', 'run_auto_sell']
@ -109,6 +111,19 @@ class AutoSellConfig:
exit_when_empty: bool = True exit_when_empty: bool = True
@dataclasses.dataclass(frozen=True)
class AutoSellRunResults:
order_details: list[fin_depo.data.TradeOrderDetails]
total_duration: datetime.timedelta
total_sleep_duration: datetime.timedelta
def total_input_amount(self) -> Decimal:
return sum(o.input_amount for o in self.order_details)
def total_output_amount(self) -> Decimal:
return sum(o.output_amount for o in self.order_details)
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):
@ -116,9 +131,13 @@ def sample_from_range(rng: random.Random, range: tuple[Any, Any]) -> Any:
return range[0] + (range[1] - range[0]) * multiplier return range[0] + (range[1] - range[0]) * multiplier
def run_auto_sell(config: AutoSellConfig): def run_auto_sell(config: AutoSellConfig) -> AutoSellRunResults:
rng = random.SystemRandom() rng = random.SystemRandom()
time_start = datetime.datetime.now(tz=datetime.UTC)
all_executed_orders: list[fin_depo.data.TradeOrderDetails] = []
total_sleep_duration = datetime.timedelta(seconds=0)
while True: while True:
# Check that account has tokens. # Check that account has tokens.
input_amount_available = config.seller.get_depo().get_amount_of_asset( input_amount_available = config.seller.get_depo().get_amount_of_asset(
@ -132,10 +151,13 @@ def run_auto_sell(config: AutoSellConfig):
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 = config.seller.place_market_order( order_details = config.seller.place_market_order(
config.input_asset, amount_to_sell, config.output_asset, config.input_asset,
amount_to_sell,
config.output_asset,
) )
print(order_details) print(order_details)
all_executed_orders.append(order_details)
# TODO: Write order details to file. # TODO: Write order details to file.
del amount_to_sell del amount_to_sell
@ -147,5 +169,26 @@ def run_auto_sell(config: AutoSellConfig):
time_to_sleep_secs = time_to_sleep.total_seconds() time_to_sleep_secs = time_to_sleep.total_seconds()
logger.info('Sleeping %s (%d seconds)', time_to_sleep, time_to_sleep_secs) logger.info('Sleeping %s (%d seconds)', time_to_sleep, time_to_sleep_secs)
config.sleep(time_to_sleep_secs) config.sleep(time_to_sleep_secs)
total_sleep_duration += time_to_sleep
del input_amount_available del input_amount_available
time_end = datetime.datetime.now(tz=datetime.UTC)
return AutoSellRunResults(
all_executed_orders,
total_duration=time_end - time_start,
total_sleep_duration=total_sleep_duration,
)
def log_results(results: AutoSellRunResults):
logger.info('Stats:')
logger.info('- Num orders: %s', len(results.order_details))
logger.info('- Total sold: %s', results.total_input_amount())
logger.info('- Total gained: %s', results.total_output_amount())
logger.info(
'- Total duration: %s (%s spent sleeping)',
results.total_duration,
results.total_sleep_duration,
)

View File

@ -6,7 +6,7 @@ from decimal import Decimal
import fin_defs import fin_defs
from . import PATH_LOG_FILE, AutoSellConfig, config, run_auto_sell from . import PATH_LOG_FILE, AutoSellConfig, config, run_auto_sell, log_results
from . import logger as module_logger from . import logger as module_logger
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -47,7 +47,9 @@ def main():
seller=seller_backend, seller=seller_backend,
sleep=time.sleep, sleep=time.sleep,
) )
run_auto_sell(auto_sell_config) results = run_auto_sell(auto_sell_config)
logging.info('Sell-offs complete')
log_results(results)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -32,7 +32,7 @@ class SellerMock(fin_depo.data.DepoFetcher):
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, # TODO? output_amount=input_amount,
fee_asset=input_asset, fee_asset=input_asset,
fee_amount=Decimal(0), fee_amount=Decimal(0),
order_id=10000000 - self.amount_left, order_id=10000000 - self.amount_left,
@ -62,7 +62,14 @@ def test_auto_run():
sleep=sleep_mock, sleep=sleep_mock,
) )
crypto_seller.run_auto_sell(config) results = crypto_seller.run_auto_sell(config)
# Check results
assert len(results.order_details) == 1000
assert results.total_sleep_duration == datetime.timedelta(seconds=1000)
assert results.total_input_amount() == 1000
assert results.total_output_amount() == 1000
# Check mocks agree
assert seller_mock.amount_left == 0 assert seller_mock.amount_left == 0
assert sleep_mock.time_slept == 1000 assert sleep_mock.time_slept == 1000