Skip to content

Commit

Permalink
Merge pull request #497 from mraniki/dev
Browse files Browse the repository at this point in the history
⬆️ 🤖 - You are standing on my toes
  • Loading branch information
mraniki authored Aug 22, 2024
2 parents 115f99c + 5dd0a55 commit f4d07ec
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 2 deletions.
3 changes: 2 additions & 1 deletion cefi/handler/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .capitalcom import CapitalHandler
from .ccxt import CcxtHandler
from .degiro import DegiroHandler
from .ib_sync import IbHandler

__all__ = ["CcxtHandler", "IbHandler", "CapitalHandler"]
__all__ = ["CapitalHandler", "CcxtHandler", "DegiroHandler", "IbHandler"]
178 changes: 178 additions & 0 deletions cefi/handler/degiro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
"""
Degiro client
"""

from datetime import date

from degiro_connector.trading.api import API as TradingAPI
from degiro_connector.trading.models.account import Format, ReportRequest
from degiro_connector.trading.models.credentials import build_credentials
from degiro_connector.trading.models.order import Action, Order, OrderType, TimeType
from loguru import logger

from .client import CexClient


class DegiroHandler(CexClient):
"""
CEX client
via Degiro API
https://github.com/Chavithra/degiro-connector
Args:
None
Returns:
None
"""

def __init__(
self,
**kwargs,
):
"""
Initialize the ccxt client
"""
super().__init__(**kwargs)
if self.name is None:
return
credentials = build_credentials(
# location="config/config.json",
override={
"username": self.user_id,
"password": self.password,
"int_account": self.broker_account_number, # From `get_client_details`
"totp_secret_key": self.secret, # For 2FA
},
)
client = TradingAPI(credentials=credentials)
client.connect()
self.accounts_data = client.get_account_info()

async def get_quote(self, instrument):
"""
Asynchronously fetches a ask/offer quote
for the specified instrument.
:param instrument: The instrument for which the quote is to be fetched.
:return: The fetched quote.
"""
# try:
# instrument = await self.replace_instrument(instrument)

# ticker = self.client.
# quote =
# logger.debug("Quote: {}", quote)
# return quote
# except Exception as e:
# logger.error("{} Error {}", self.name, e)

async def get_account_balance(self):
"""
return account balance of
a given ccxt exchange
Args:
None
Returns:
balance
"""
return self.client.get_account_report(
report_request=ReportRequest(
country="FR",
lang="fr",
format=Format.CSV,
from_date=date(year=date.today().year - 1, month=1, day=1),
to_date=date.today(),
),
raw=False,
)

async def get_account_position(self):
"""
Return account position.
of a given exchange
Args:
None
Returns:
position
"""
return self.client.get_position_report(
report_request=ReportRequest(
country="FR",
lang="fr",
format=Format.XLS,
from_date=date(year=date.today().year - 1, month=1, day=1),
to_date=date.today(),
),
raw=False,
)

async def pre_order_checks(self, order_params):
""" """
return True

async def get_trading_asset_balance(self):
""" """
return self.client.fetchBalance()[f"{self.trading_asset}"]["free"]

async def execute_order(self, order_params):
"""
Execute order
Args:
order_params (dict):
action(str)
instrument(str)
quantity(int)
Returns:
trade_confirmation(dict)
"""
try:
action = order_params.get("action")
instrument = await self.replace_instrument(order_params.get("instrument"))
quantity = order_params.get("quantity", self.trading_risk_amount)
if not action or not instrument:
raise ValueError("Missing required parameters: action or instrument")
logger.debug(f"quantity {quantity}")
amount = await self.get_order_amount(
quantity=quantity,
instrument=instrument,
is_percentage=self.trading_risk_percentage,
)
if not amount:
raise ValueError("Failed to calculate order amount")
logger.debug(f"amount {amount}")
pre_order_checks = await self.pre_order_checks(order_params)
if not pre_order_checks:
raise ValueError("Pre-order checks failed")
order = Order(
buy_sell=Action.BUY if action == "BUY" else Action.SELL,
order_type=OrderType.LIMIT,
price=12.1,
product_id=72160,
size=amount,
time_type=TimeType.GOOD_TILL_DAY,
)
if checking_response := self.client.check_order(order=order):
if confirmation_response := self.client.confirm_order(
confirmation_id=checking_response.confirmation_id,
order=order,
):
logger.debug("Confirmation: {}", confirmation_response)
return await self.get_trade_confirmation(order, instrument, action)
except Exception as e:
logger.error(f"{self.name} Error {e}")
return f"Error executing {self.name}"
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ loguru = ">=0.6"
ccxt = "^4.2.80"
ib_insync = "0.9.86"
capitalcom-python = "0.2.3"
degiro-connector = "3.0.22"

[ tool.poetry.group.dev.dependencies]
python-semantic-release = ">=8.0.8"
Expand Down Expand Up @@ -176,7 +177,7 @@ overgeneral-exceptions = [
[tool.poetry.group.test.dependencies]
pytest = "^8.0.0"
pytest-cov = "^5.0.0"
pytest-asyncio = "^0.23.0"
pytest-asyncio = "^0.24.0"
pytest-mock = "^3.11.1"
pytest-loguru = "^0.4.0"

Expand Down

0 comments on commit f4d07ec

Please sign in to comment.