mirror of
https://github.com/Ichinga-Samuel/aiomql.git
synced 2026-08-21 15:58:09 +00:00
127 lines
5.4 KiB
Python
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])
|