Files
aiomql/src/aiomql/positions.py
T
2024-05-05 00:08:57 +01:00

127 lines
5.4 KiB
Python

"""Handle Open positions."""
import asyncio
from logging import getLogger
from .core import MetaTrader, TradePosition, TradeAction, OrderType
from .order import Order
logger = getLogger(__name__)
class Positions:
"""Get Open Positions.
Attributes:
symbol (str): Financial instrument name.
group (str): The filter for arranging a group of necessary symbols. Optional named parameter.
If the group is specified, the function returns only positions meeting a specified criteria for a symbol.
ticket (int): Position ticket.
mt5 (MetaTrader): MetaTrader instance.
"""
mt5: MetaTrader
def __init__(self, *, symbol: str = "", group: str = "", ticket: int = 0):
"""Get Open Positions.
Keyword Args:
symbol (str): Financial instrument name.
group (str): The filter for arranging a group of necessary symbols. Optional named parameter. If the group
is specified, the function returns only positions meeting a specified criteria for a symbol name.
ticket (int): Position ticket
"""
self.mt5 = MetaTrader()
self.symbol = symbol
self.group = group
self.ticket = ticket
async def positions_total(self) -> int:
"""Get the number of open positions.
Returns:
int: Return total number of open positions
"""
return await self.mt5.positions_total()
async def positions_get(self, symbol: str = '', group: str = '', ticket: int = 0, retries=3) -> list[TradePosition]:
"""Get open positions with the ability to filter by symbol or ticket.
Keyword Args:
symbol (str): Financial instrument name.
group (str): The filter for arranging a group of necessary symbols. Optional named parameter. If the group
is specified, the function returns only positions meeting a specified criteria for a symbol name.
ticket (int): Position ticket
Returns:
list[TradePosition]: A list of open trade positions
"""
if retries < 1:
logger.warning(f'Failed to get positions for {symbol or self.symbol}. {self.mt5.error}')
return []
positions = await self.mt5.positions_get(group=group or self.group, symbol=symbol or self.symbol,
ticket=ticket or self.ticket)
if positions is not None:
return [TradePosition(**pos._asdict()) for pos in positions]
if self.mt5.error.is_connection_error():
await asyncio.sleep(retries)
return await self.positions_get(symbol, group, ticket, retries - 1)
logger.warning(f'Failed to get positions for {symbol or self.symbol}. {self.mt5.error}')
return []
async def position_get(self, *, ticket: int) -> TradePosition:
"""Get an open position by ticket.
Args:
ticket (int): Position ticket.
Returns:
TradePosition: Return an open position
"""
positions = await self.positions_get(ticket=ticket)
position = positions[0] if positions else None
if position is None:
raise ValueError(f'Position with ticket {ticket} not found')
assert position.ticket == ticket, f'Position with ticket {ticket} not found'
return position
async def close(self, *, ticket: int, symbol: str, price: float, volume: float, order_type: OrderType):
"""Close an open position for the trading account using the ticket and other parameters.
Args:
ticket (int): Position ticket.
symbol (str): Financial instrument name.
price (float): Closing price.
volume (float): Volume to close.
order_type (OrderType): Order type.
"""
order = Order(action=TradeAction.DEAL, price=price, position=ticket, symbol=symbol, volume=volume,
type=order_type.opposite)
return await order.send()
async def close_by(self, pos: TradePosition):
"""Close an open position for the trading account."""
order = Order(position=pos.ticket, symbol=pos.symbol, volume=pos.volume, type=pos.type.opposite,
price=pos.price_current)
return await order.send()
async def close_position(self, *, position: TradePosition):
"""Close an open position for the trading account. Using a position object."""
order = Order(position=position.ticket, symbol=position.symbol, volume=position.volume,
type=position.type.opposite, price=position.price_current)
return await order.send()
async def close_all(self, symbol: str = '', group: str = '') -> int:
"""Close all open positions for the trading account. Specify a symbol or group to filter positions.
Keyword Args:
symbol (str): Financial instrument name.
group (str): The filter for specifying a group of symbols.
Returns:
int: Return number of positions closed.
"""
symbol = symbol or self.symbol
group = group or self.group
positions = [pos for pos in await self.positions_get(symbol=symbol, group=group)]
orders = [self.close_position(position=pos) for pos in positions]
results = await asyncio.gather(*[order for order in orders], return_exceptions=True)
return len([res for res in results if (res and res.retcode) == 10009])