Skip to content

Commit

Permalink
Merge pull request #79 from Pasta-fantasia/77-noisetrader-v0
Browse files Browse the repository at this point in the history
77 noisetrader v0
  • Loading branch information
fransimo committed Jul 6, 2024
2 parents 24aef26 + 64f5dd2 commit 3fb246c
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 20 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 2.4.0
- feat: NoiseTrader v0 #77
- small fixes

## 2.3.3
- fix: Amount to close is insufficient for trade #75
- test: tests and test data
Expand Down
2 changes: 2 additions & 0 deletions elena/domain/ports/metrics_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
ORDER_STOP_LOSS_CLOSED = "OrderStopLossClosed"
ORDER_BUY_MARKET = "OrderBuyMarket"
ORDER_SELL_MARKET = "OrderSellMarket"
ESTIMATED_LAST_CLOSE = "EstimatedLastClose"
ESTIMATED_SALE_PRICE = "EstimatedSalePrice"


@runtime_checkable
Expand Down
4 changes: 2 additions & 2 deletions elena/domain/services/bot_status_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def _close_individual_trade_on_new_order(
rtn = rtn + individual_rtn
bot_status.closed_trades.append(trade)
self._notifications_manager.medium(
f"Closed trade for {trade.size} on {order.pair} with beneift of {individual_rtn}. Entry price at: {trade.entry_price}, exit price at: {trade.exit_price}. Entry cost at: {trade.entry_cost}, exit cost at: {trade.exit_cost}"
f"Closed trade for {trade.size} on {order.pair} with benefit of {individual_rtn}. Entry price at: {trade.entry_price}, exit price at: {trade.exit_price}. Entry cost at: {trade.entry_cost}, exit cost at: {trade.exit_cost}"
)
self._metrics_manager.gauge("benefit", bot_status.bot_id, individual_rtn, tags=["trades", f"exchange:{order.exchange_id.value}"])
return round(amount_to_close - trade.size, self.precision_amount), rtn
Expand Down Expand Up @@ -93,7 +93,7 @@ def _close_trades_on_new_updated_order(self, bot_status: BotStatus, order: Order
amount_to_close, rtn = self._close_individual_trade_on_new_order(bot_status, trade, order, amount_to_close, rtn)

if amount_to_close > 0: # TODO: how to pass min_amount?
self._logger.error("The order size is bigger than any trade. {amount_to_close} left to close of {order.amount}.")
self._logger.error(f"The order size is bigger than any trade. {amount_to_close} left to close of {order.amount}.")
pass

return rtn
Expand Down
53 changes: 37 additions & 16 deletions elena/domain/services/generic_bot.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import time
from typing import Dict, Optional
from typing import Dict, Optional, List

import pandas as pd

Expand All @@ -16,7 +16,7 @@
from elena.domain.ports.bot import Bot
from elena.domain.ports.exchange_manager import ExchangeManager
from elena.domain.ports.logger import Logger
from elena.domain.ports.metrics_manager import MetricsManager, ORDER_CANCELLED, ORDER_STOP_LOSS, ORDER_BUY_MARKET, ORDER_SELL_MARKET, ORDER_STOP_LOSS_CLOSED
from elena.domain.ports.metrics_manager import MetricsManager, ORDER_CANCELLED, ORDER_STOP_LOSS, ORDER_BUY_MARKET, ORDER_SELL_MARKET, ORDER_STOP_LOSS_CLOSED, ESTIMATED_LAST_CLOSE, ESTIMATED_SALE_PRICE
from elena.domain.ports.notifications_manager import NotificationsManager
from elena.domain.ports.strategy_manager import StrategyManager
from elena.domain.services.bot_status_logic import BotStatusLogic
Expand All @@ -38,6 +38,7 @@ class GenericBot(Bot):
_metrics_manager: MetricsManager
_notifications_manager: NotificationsManager
_bot_status_logic: BotStatusLogic
_order_book_cache: OrderBook

def init(
self,
Expand Down Expand Up @@ -74,6 +75,8 @@ def init(
self._bot_status_logic = BotStatusLogic(logger, metrics_manager, notifications_manager, precision_amount, precision_price)
self.status.budget.precision_price = precision_price

self._order_book_cache = None

self._update_orders_status()

def new_trade_manual(self, size: float, entry_price: float, exit_order_id, exit_price: float) -> str:
Expand Down Expand Up @@ -201,12 +204,17 @@ def price_to_precision(self, price: float) -> Optional[float]:
self._logger.error("Error getting price to precision: %s", err, exc_info=1)
return None

def get_order_book(self) -> Optional[OrderBook]:
def get_order_book(self, use_cache: bool = False) -> Optional[OrderBook]:
if use_cache and self._order_book_cache:
return self._order_book_cache

try:
return self.exchange_manager.read_order_book(
order_book = self.exchange_manager.read_order_book(
self.exchange,
pair=self.pair,
)
self._order_book_cache = order_book
return order_book
except Exception as err:
print(f"Error getting order book: {err}")
self._logger.error("Error getting order book: %s", err, exc_info=1)
Expand Down Expand Up @@ -276,7 +284,7 @@ def create_limit_buy_order(self, amount, price) -> Optional[Order]:
def create_limit_sell_order(self, amount, price) -> Optional[Order]:
raise NotImplementedError

def create_market_buy_order(self, amount) -> Optional[Order]:
def create_market_buy_order(self, amount: float) -> Optional[Order]:
try:
params = {"type": "spot"}

Expand All @@ -300,7 +308,7 @@ def create_market_buy_order(self, amount) -> Optional[Order]:
self._logger.error("Error creating market buy order: %s", err, exc_info=1)
return None

def create_market_sell_order(self, amount) -> Optional[Order]:
def create_market_sell_order(self, amount: float, trades_to_close: List[Trade] = []) -> Optional[Order]:
try:
params = {"type": "spot"}

Expand All @@ -315,7 +323,12 @@ def create_market_sell_order(self, amount) -> Optional[Order]:
)
self._logger.info("Placed market sell: %s", order)
self._metrics_manager.counter(ORDER_SELL_MARKET, self.id, 1, [f"exchange:{self.bot_config.exchange_id.value}"])
self._notifications_manager.low(f"Placed market sell: {order.id} for {order.amount} {order.pair.base} at {order.average} {order.pair.quote} , getting: {order.cost}{order.pair.quote}")
self._notifications_manager.low(f"Placed market sell: {order.id} for {order.amount} {order.pair.base} at {order.average} {order.pair.quote}, getting: {order.cost}{order.pair.quote}")

for trade in trades_to_close:
trade.exit_order_id = order.id
trade.exit_time = order.timestamp
trade.exit_price = order.average

self.status = self._bot_status_logic.register_new_order_on_trades(self.status, order)
return order
Expand All @@ -336,6 +349,8 @@ def fetch_order(self, order_id: str) -> Optional[Order]:
self._logger.error("Error fetching order: %s", err, exc_info=1)
return None



def get_estimated_last_close(self) -> Optional[float]:
# https://docs.ccxt.com/#/?id=ticker-structure
# Although some exchanges do mix-in order book's top bid/ask prices into their tickers
Expand All @@ -345,21 +360,27 @@ def get_estimated_last_close(self) -> Optional[float]:
# imposing stricter rate limits on these queries. If you need a unified way to access bids and asks you
# should use fetchL[123]OrderBook family instead.
# The idea was to use fetch_ticker[close]
try:
order_book = self.exchange_manager.read_order_book(
self.exchange,
pair=self.pair,
)
except Exception as err:
print(f"Error getting estimated last close: {err}")
self._logger.error("Error getting estimated last close %s", exc_info=1)
raise err

order_book = self.get_order_book()
try:
# TODO order_book.bids and asks could be empty
last_bid = order_book.bids[0].price
last_ask = order_book.asks[0].price
estimated_last_close = (last_bid + last_ask) / 2
self._metrics_manager.gauge(ESTIMATED_LAST_CLOSE, self.id, estimated_last_close, ["indicator"])
return estimated_last_close
except Exception as err: # noqa: F841
return None

def get_estimated_sell_price_from_cache(self) -> Optional[float]:
# https://docs.ccxt.com/#/?id=ticker-structure
order_book = self.get_order_book(use_cache=True)

try:
# TODO order_book.bids and asks could be empty
estimated_sell_price = (order_book.bids[0].price + order_book.bids[1].price + order_book.bids[2].price) / 3
self._metrics_manager.gauge(ESTIMATED_SALE_PRICE, self.id, estimated_sell_price, ["indicator"])

return estimated_sell_price
except Exception as err: # noqa: F841
return None
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ schedule~=1.1.0
pydantic~=1.10.2
ccxt~=4.0.32
pandas~=2.0.3
cron-converter~=1.0.2
cron-converter~=1.0.2
numpy~=1.26.2
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = elena
version = 2.3.3
version = 2.4.0
author = "L Software Foundation"
author_email = "fransimo@gmail.com, pjover@gmail.com"
description = Hexagonal multi exchange crypto currency strategy executor
Expand Down

0 comments on commit 3fb246c

Please sign in to comment.