mirror of
https://github.com/Ichinga-Samuel/aiomql.git
synced 2026-08-07 17:27:45 +00:00
verion 3.0.4
This commit is contained in:
+11
-9
@@ -8,14 +8,16 @@ class Session()
|
||||
A session is a time period between two datetime.time objects specified in utc.
|
||||
|
||||
### Attributes:
|
||||
|Name|Type|Description|Default|
|
||||
|---|---|---|---|
|
||||
|**start**|**datetime.time**|The start time of the session.|None|
|
||||
|**end**|**datetime.time**|The end time of the session.|None|
|
||||
|**on_start**|**str**|The action to take when the session starts. Default is None.|None|
|
||||
|**on_end**|**str**|The action to take when the session ends. Default is None.|None|
|
||||
|**custom_start**|**Callable**|A custom function to call when the session starts. Default is None.|None|
|
||||
|**custom_end**|**Callable**|A custom function to call when the session ends. Default is None.|None|
|
||||
|Name| Type | Description | Default |
|
||||
|---|----------------|------------------------------------------------------------------------|----|
|
||||
|**start**| **datetime.time** | The start time of the session. | None |
|
||||
|**end**| **datetime.time** | The end time of the session. | None |
|
||||
|**on_start**| **Literal['close_all', 'close_win', 'close_loss', 'custom_start']** | The action to take when the session starts. Default is None. | None |
|
||||
|**on_end**| **Literal['close_all', 'close_win', 'close_loss', 'custom_end']** | The action to take when the session ends. Default is None. | None |
|
||||
|**custom_start**| **Callable** | A custom function to call when the session starts. Default is None. | None |
|
||||
|**custom_end**| **Callable** | A custom function to call when the session ends. Default is None. | None |
|
||||
|**name**| **str** | The name of the session. Default is a combination of start and finish. | |
|
||||
|**seconds**| **set[int]** | The set of seconds in the session. | None |
|
||||
|
||||
### Methods:
|
||||
|Name|Description|
|
||||
@@ -23,7 +25,6 @@ A session is a time period between two datetime.time objects specified in utc.
|
||||
|**begin**|Call the action specified in on_start or custom_start.|
|
||||
|**close**|Call the action specified in on_end or custom_end.|
|
||||
|**action**|Used by begin and close to call the action specified.|
|
||||
|**delta**|Get the timedelta of a datetime.time object.|
|
||||
|**until**|Get the seconds until the session starts from the current time.|
|
||||
|
||||
### \_\_init\_\_
|
||||
@@ -49,6 +50,7 @@ Create a session.
|
||||
|**on_end**| **Literal['close_all', 'close_win', 'close_loss', 'custom_end']** | The action to take when the session ends. Default is None. | None |
|
||||
|**custom_start**| **Callable** | A custom function to call when the session starts. Default is None. | None |
|
||||
|**custom_end**| **Callable** | A custom function to call when the session ends. Default is None. | None |
|
||||
|**name**| **str** | The name of the session. Default is None. | None |
|
||||
|
||||
### begin
|
||||
```python
|
||||
|
||||
+17
-5
@@ -162,11 +162,12 @@ This is a dummy method that returns the minimum volume of the symbol. It is mean
|
||||
Checkout Forex Symbol implementation in [ForexSymbol](#forexsymbol)
|
||||
|
||||
#### Arguments:
|
||||
|Name| Type | Description | Default |
|
||||
|---|--------------------|-----------------------------|-------------------|
|
||||
|**amount**| **float** | Amount to risk in the trade | None |
|
||||
|**pips**| **float** | Number of pips to target | None |
|
||||
|**use_minimum**| **bool** | If True, the minimum volume is returned if the computed volume is less than the minimum volume. | True |
|
||||
| Name | Type | Description | Default |
|
||||
|----------------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
|
||||
| **amount** | **float** | Amount to risk in the trade | None |
|
||||
| **pips** | **float** | Number of pips to target | None |
|
||||
| **use_limits** | **bool** | If True, the minimum volume is returned if the computed volume is less than the minimum volume and the maximum volume is returned if the computed volume is greater than the maximum volume for the symbol | False |
|
||||
|
||||
#### Returns:
|
||||
|Type|Description|
|
||||
|---|---|
|
||||
@@ -308,3 +309,14 @@ Get ticks for the specified date range from the MetaTrader 5 terminal.
|
||||
|Exception|Description|
|
||||
|---|---|
|
||||
|**ValueError**|If request was unsuccessful and None was returned|
|
||||
|
||||
### compute_volume
|
||||
```python
|
||||
async def compute_volume(*,
|
||||
amount: float,
|
||||
pips: float,
|
||||
use_limits: bool = True) -> float
|
||||
```
|
||||
Computes the volume of a trade based on the amount and the number of pips to target.
|
||||
This is a dummy method that returns the minimum volume of the symbol. It is meant to be overridden by a subclass
|
||||
Checkout Forex Symbol implementation in [ForexSymbol](#forexsymbol)
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
import logging
|
||||
|
||||
from aiomql.lib import FingerTrap
|
||||
from aiomql import Bot, Account, ForexSymbol
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
def build_bot():
|
||||
# Either initialize an account here with your login details here or set them in the aiomql.json file.
|
||||
# acc = Account(login=1111111111, password='*******', server='Deriv-Demo')
|
||||
bot = Bot()
|
||||
|
||||
# Prebuilt strategy from the library.
|
||||
# Disclaimer: These strategy is only for demonstration purposes.
|
||||
params = {'trend_candles_count': 500}
|
||||
st1 = FingerTrap(symbol=ForexSymbol(name='GBPUSD'), params=params)
|
||||
st3 = FingerTrap(symbol=ForexSymbol(name='AUDUSD'), params=params)
|
||||
st4 = FingerTrap(symbol=ForexSymbol(name='USDCAD'), params=params)
|
||||
st5 = FingerTrap(symbol=ForexSymbol(name='USDJPY'), params=params)
|
||||
st6 = FingerTrap(symbol=ForexSymbol(name='EURGBP'), params=params)
|
||||
bot.add_strategies([st1, st3, st4, st5, st6])
|
||||
bot.execute()
|
||||
|
||||
|
||||
build_bot()
|
||||
@@ -0,0 +1,38 @@
|
||||
from datetime import time
|
||||
import logging
|
||||
|
||||
from aiomql.lib import FingerTrap
|
||||
from aiomql import Bot, Account, ForexSymbol, Session, Sessions
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
def build_bot():
|
||||
# Either initialize an account here with your login details here or set them in the aiomql.json file.
|
||||
# acc = Account(login=1234567, password='*******', server='Broker-Server')
|
||||
bot = Bot()
|
||||
|
||||
# Prebuilt strategy from the library.
|
||||
# Disclaimer: These strategy is only for demonstration purposes.
|
||||
# The author of this library is not responsible for any losses incurred from using this strategy.
|
||||
|
||||
# using trade sessions is optional. the strategy will run with a default session of 24 hours if not specified.
|
||||
# session start and end times are in UTC. Make sure to convert to UTC if you are in a different timezone.
|
||||
# sessions can be used to close positions at the end of a trading session.
|
||||
sess = Session(name='London', start=8, end=time(hour=15, minute=30), on_end='close_all')
|
||||
sess2 = Session(name='New York', start=13, end=time(hour=20, minute=30))
|
||||
sess3 = Session(name='Tokyo', start=23, end=time(hour=6, minute=30))
|
||||
sessions = Sessions(sess, sess2, sess3)
|
||||
|
||||
# configurable parameters for the strategy
|
||||
params = {'trend_candles_count': 500, 'fast_period': 8}
|
||||
st1 = FingerTrap(symbol=ForexSymbol(name='GBPUSD'), params=params, sessions=sessions)
|
||||
st3 = FingerTrap(symbol=ForexSymbol(name='AUDUSD'), params=params, sessions=sessions)
|
||||
st4 = FingerTrap(symbol=ForexSymbol(name='USDCAD'), params=params, sessions=sessions)
|
||||
st5 = FingerTrap(symbol=ForexSymbol(name='USDJPY'), params=params, sessions=sessions)
|
||||
st6 = FingerTrap(symbol=ForexSymbol(name='EURGBP'), params=params, sessions=sessions)
|
||||
bot.add_strategies([st1, st3, st4, st5, st6])
|
||||
bot.execute()
|
||||
|
||||
|
||||
build_bot()
|
||||
@@ -1,47 +0,0 @@
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import asyncio
|
||||
import random
|
||||
import time
|
||||
|
||||
se = set()
|
||||
def fun(arg):
|
||||
while True:
|
||||
time.sleep(10)
|
||||
print('sleep')
|
||||
# print('sleeping')
|
||||
# await asyncio.sleep(random.randint(1, 10))
|
||||
# print('wake up')
|
||||
|
||||
|
||||
def nuf():
|
||||
while True:
|
||||
# time.sleep(5)
|
||||
print('awake')
|
||||
|
||||
|
||||
def main(f):
|
||||
asyncio.run(f())
|
||||
|
||||
|
||||
async def run():
|
||||
# loop = asyncio.get_running_loop()
|
||||
with ThreadPoolExecutor(max_workers=10) as exe:
|
||||
exe.submit(fun, 10)
|
||||
exe.submit(nuf)
|
||||
# r.cancel()
|
||||
# print(r.done())
|
||||
# return r.result()
|
||||
|
||||
|
||||
|
||||
asyncio.run(run())
|
||||
|
||||
# ars = (1, 3, 4)
|
||||
#
|
||||
# def check(f, args):
|
||||
# print(*args)
|
||||
#
|
||||
#
|
||||
# b = {check: (3, ars)}
|
||||
|
||||
# [k(v[0], v[1]) for k,v in b.items()]
|
||||
+49
-31
@@ -10,6 +10,21 @@ from .positions import Positions
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
def delta(obj: time):
|
||||
"""Get the timedelta of a datetime.time object.
|
||||
|
||||
Args:
|
||||
obj (datetime.time): A datetime.time object.
|
||||
"""
|
||||
return timedelta(hours=obj.hour, minutes=obj.minute, seconds=obj.second, microseconds=obj.microsecond)
|
||||
|
||||
|
||||
def seconds(start: time, end: time) -> set[int]:
|
||||
if start > end:
|
||||
return set(range(delta(start).seconds, 86400)) | set(range(0, delta(end).seconds))
|
||||
return set(range(delta(start).seconds, delta(end).seconds))
|
||||
|
||||
|
||||
class Session:
|
||||
"""A session is a time period between two datetime.time objects specified in utc.
|
||||
|
||||
@@ -20,6 +35,8 @@ class Session:
|
||||
on_end (str): The action to take when the session ends. Default is None.
|
||||
custom_start (Callable): A custom function to call when the session starts. Default is None.
|
||||
custom_end (Callable): A custom function to call when the session ends. Default is None.
|
||||
name (str): A name for the session. Default is a combination of start and end.
|
||||
seconds (set[int]): A set of seconds between start and end.
|
||||
|
||||
Methods:
|
||||
begin: Call the action specified in on_start or custom_start.
|
||||
@@ -31,7 +48,7 @@ class Session:
|
||||
def __init__(self, *, start: int | time, end: int | time,
|
||||
on_start: Literal['close_all', 'close_win', 'close_loss', 'custom_start'] = None,
|
||||
on_end: Literal['close_all', 'close_win', 'close_loss', 'custom_end'] = None,
|
||||
custom_start: Callable = None, custom_end: Callable = None):
|
||||
custom_start: Callable = None, custom_end: Callable = None, name: str = ''):
|
||||
"""Create a session.
|
||||
|
||||
Keyword Args:
|
||||
@@ -43,21 +60,28 @@ class Session:
|
||||
ends. Default is None.
|
||||
custom_start (Callable): A custom function to call when the session starts. Default is None.
|
||||
custom_end (Callable): A custom function to call when the session ends. Default is None.
|
||||
name (str): A name for the session. Default is a combination of start and end.
|
||||
"""
|
||||
self.start = start if isinstance(start, time) else time(hour=start)
|
||||
self.end = end if isinstance(end, time) else time(hour=end)
|
||||
self.__from = self.delta(self.start)
|
||||
self.__to = self.delta(self.end)
|
||||
self.on_start = on_start
|
||||
self.on_end = on_end
|
||||
self.custom_start = custom_start
|
||||
self.custom_end = custom_end
|
||||
self.name = name or f'{self.start} - {self.end}'
|
||||
self.seconds = seconds(self.start, self.end)
|
||||
|
||||
def __contains__(self, item: time):
|
||||
return self.start <= item < self.end
|
||||
return delta(item).seconds in self.seconds
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.start}-->{self.name}-->{self.end}' if self.name else f'{self.start}-->{self.end}'
|
||||
|
||||
def __repr__(self):
|
||||
return f'{self.start}<-{len(self)}->{self.end}'
|
||||
return f'{self.start}-->{self.end}'
|
||||
|
||||
def __len__(self):
|
||||
return (delta(self.start) - delta(self.end)).seconds
|
||||
|
||||
async def begin(self):
|
||||
"""Call the action specified in on_start or custom_start."""
|
||||
@@ -111,21 +135,9 @@ class Session:
|
||||
except Exception as exe:
|
||||
logger.warning(f'Failed to call action {action} due to {exe}')
|
||||
|
||||
@staticmethod
|
||||
def delta(obj: time):
|
||||
"""Get the timedelta of a datetime.time object.
|
||||
|
||||
Args:
|
||||
obj (datetime.time): A datetime.time object.
|
||||
"""
|
||||
return timedelta(hours=obj.hour, minutes=obj.minute, seconds=obj.second, microseconds=obj.microsecond)
|
||||
|
||||
def __len__(self):
|
||||
return (self.__to - self.__from).seconds
|
||||
|
||||
def until(self):
|
||||
"""Get the seconds until the session starts from the current time."""
|
||||
return (self.__from - self.delta(datetime.utcnow().time())).seconds
|
||||
"""Get the seconds until the session starts from the current time in seconds."""
|
||||
return (delta(self.start) - delta(datetime.utcnow().time())).seconds
|
||||
|
||||
|
||||
class Sessions:
|
||||
@@ -143,8 +155,8 @@ class Sessions:
|
||||
"""
|
||||
def __init__(self, *sessions: Session):
|
||||
self.sessions = list(sessions)
|
||||
self.sessions.sort(key=lambda x: x.start)
|
||||
self.current_session = sessions[0]
|
||||
self.sessions.sort(key=lambda x: (x.start, x.end))
|
||||
self.current_session = None
|
||||
|
||||
def find(self, obj: time) -> Session | None:
|
||||
"""Find a session that contains a datetime.time object.
|
||||
@@ -172,7 +184,7 @@ class Sessions:
|
||||
for session in self.sessions:
|
||||
if obj < session.start:
|
||||
return session
|
||||
return self.sessions[-1]
|
||||
return self.sessions[0]
|
||||
|
||||
def __contains__(self, item: time):
|
||||
return True if self.find(item) is not None else False
|
||||
@@ -187,15 +199,21 @@ class Sessions:
|
||||
async def check(self):
|
||||
"""Check if the current session has started and if not, wait until it starts."""
|
||||
now = datetime.utcnow().time()
|
||||
if now in self.current_session:
|
||||
return
|
||||
await self.current_session.close()
|
||||
|
||||
current_session = self.find(now)
|
||||
if current_session is None:
|
||||
current_session = self.find_next(now)
|
||||
secs = current_session.until() + 10
|
||||
print(f'sleeping for {secs} seconds until next session')
|
||||
await sleep(secs)
|
||||
if current_session:
|
||||
if self.current_session:
|
||||
if self.current_session == current_session:
|
||||
return
|
||||
await self.current_session.close()
|
||||
|
||||
self.current_session = current_session
|
||||
await self.current_session.begin()
|
||||
return
|
||||
|
||||
await self.current_session.close() if self.current_session else ...
|
||||
current_session = self.find_next(now)
|
||||
secs = current_session.until() + 10
|
||||
print(f'sleeping for {secs} seconds until next {current_session} session')
|
||||
await sleep(secs)
|
||||
self.current_session = current_session
|
||||
await self.current_session.begin()
|
||||
|
||||
@@ -135,17 +135,15 @@ class Symbol(SymbolInfo):
|
||||
"""
|
||||
return await self.mt5.market_book_release(self.name)
|
||||
|
||||
async def compute_volume(self, *, amount: float, pips: float, use_minimum: bool = True) -> float:
|
||||
async def compute_volume(self, *, amount: float, pips: float, use_limits: bool = True) -> float:
|
||||
"""Computes the volume of a trade based on the amount and the number of pips to target.
|
||||
This is a dummy method that returns the minimum volume of the symbol. It is meant to be overridden by a subclass
|
||||
Checkout Forex Symbol implementation in src\aiomql\lib\ForexSymbol.py
|
||||
that implements the computation of volume.
|
||||
|
||||
Args:
|
||||
amount (float): Amount to risk in the trade
|
||||
pips (float): Number of pips to target
|
||||
|
||||
Keyword Args:
|
||||
use_minimum (bool): If True, the minimum volume is returned if the computed volume is less than the minimum volume.
|
||||
use_limits (bool): If True, the computed volume is rounded to the nearest step and checked against
|
||||
|
||||
Returns:
|
||||
float: Returns the volume of the trade
|
||||
|
||||
@@ -54,7 +54,7 @@ class Trader:
|
||||
"""
|
||||
# check if pips is passed in as a keyword argument, if not use the pips attribute of the ram instance
|
||||
pips = kwargs.get('pips', 0) or self.ram.pips
|
||||
self.order.volume = self.ram.volume or await self.ram.get_volume(symbol=self.symbol, pips=pips)
|
||||
self.order.volume = kwargs.get('volume', self.ram.volume) or await self.ram.get_volume(symbol=self.symbol, pips=pips)
|
||||
self.order.type = order_type
|
||||
await self.set_order_limits(pips=pips)
|
||||
|
||||
@@ -82,7 +82,7 @@ class Trader:
|
||||
|
||||
Args:
|
||||
order_type (OrderType): Type of order
|
||||
params: parameters to be saved with the trade
|
||||
params: parameters of the trading strategy used to place the trade
|
||||
kwargs: keyword arguments as required for the specific trader
|
||||
"""
|
||||
try:
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
import pytz
|
||||
from aiomql import MetaTrader, Symbol, TimeFrame, Account, ForexSymbol
|
||||
|
||||
|
||||
async def main():
|
||||
async with Account() as account:
|
||||
d = datetime.now()
|
||||
start = d.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=pytz.timezone('UTC'))
|
||||
print(start.timestamp())
|
||||
end = d.replace(hour=7, minute=0, second=0, microsecond=0, tzinfo=pytz.timezone('UTC'))
|
||||
# print(end.timestamp())
|
||||
s = ForexSymbol(name='EURUSD')
|
||||
s1 = ForexSymbol(name='USDJPY')
|
||||
await s.init()
|
||||
await s1.init()
|
||||
# t = await s.copy_ticks_range(date_from=start, date_to=end)
|
||||
# t1 = await s1.copy_ticks_range(date_from=start, date_to=end)
|
||||
r = await s1.copy_rates_range(date_from=start, date_to=end, timeframe=TimeFrame.M1)
|
||||
# rc = await s1.copy_rates_from(date_from=end, timeframe=TimeFrame.M15, count=96)
|
||||
print(datetime.fromtimestamp(r[0].time, tz=pytz.timezone('UTC')), datetime.fromtimestamp(r[-1].time), len(r))
|
||||
# f = await s.copy_ticks_range(date_from=start, date_to=end)
|
||||
# print(datetime.fromtimestamp(f[0].time), datetime.fromtimestamp(f[-1].time), len(f))
|
||||
# print(len(f), len(rc), rc[50].open)
|
||||
# print(len(r), r[-1].time, len(rc), rc[-1].time - rc[-2].time, end.timestamp(),rc[0].time)
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,28 +0,0 @@
|
||||
# import asyncio
|
||||
# from pprint import pprint as pp
|
||||
# from aiomql import Order, Account, ForexSymbol, RAM, OrderType
|
||||
#
|
||||
#
|
||||
# async def test_send_order():
|
||||
# await Account().sign_in()
|
||||
# symbol = ForexSymbol(name='Volatility 50 Index')
|
||||
# await symbol.init()
|
||||
# tick = await symbol.info_tick()
|
||||
# pips = 100
|
||||
# volume = await symbol.compute_volume(amount=100, pips=pips)
|
||||
# sls = symbol.trade_stops_level
|
||||
# cls = pips * symbol.pip
|
||||
# print(sls, cls)
|
||||
# sl = tick.ask - (cls)
|
||||
# tp = tick.ask + (cls)
|
||||
# sls = symbol.trade_stops_level
|
||||
# po = sls * symbol.point
|
||||
# pi = po * 10
|
||||
# # print(sls, po, pi, sl)
|
||||
# print(volume)
|
||||
# order = Order(symbol=symbol.name, type=OrderType.BUY, sl=sl, tp=tp, volume=volume, price=tick.ask)
|
||||
# res = await order.send()
|
||||
# pp(res.dict)
|
||||
|
||||
asyncio.run(test_send_order())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user