add testdata class

This commit is contained in:
Ichinga Samuel
2024-08-22 17:31:21 +01:00
parent 1187bcc2dd
commit 64850d79c1
5 changed files with 79 additions and 32 deletions
+25 -3
View File
@@ -4,7 +4,7 @@ from .constants import BookType, TradeAction, OrderType, OrderTime, OrderFilling
DealReason, SymbolChartMode, SymbolTradeMode, SymbolCalcMode, SymbolOptionMode, SymbolOrderGTCMode, \
SymbolOptionRight, \
SymbolTradeExecution, SymbolSwapMode, DayOfWeek, AccountTradeMode, AccountStopOutMode, AccountMarginMode, \
OrderReason
OrderReason, TickFlag
from .base import Base
@@ -334,9 +334,9 @@ class SymbolInfo(Base):
path: str
def __init__(self, **kwargs):
if 'name' not in kwargs:
if name := kwargs.pop('name', None):
raise AttributeError('Symbol Object Must be initialized with a name')
self.name = kwargs.pop('name')
self.name = name
super().__init__(**kwargs)
def __repr__(self):
@@ -351,6 +351,28 @@ class SymbolInfo(Base):
def __hash__(self):
return hash(self.name)
class TickInfo(Base):
"""Price Tick of a Financial Instrument.
Attributes:
time (int): Time of the last prices update for the symbol
bid (float): Current Bid price
ask (float): Current Ask price
last (float): Price of the last deal (Last)
volume (float): Volume for the current Last price
time_msc (int): Time of the last prices update for the symbol in milliseconds
flags (TickFlag): Tick flags
volume_real (float): Volume for the current Last price
Index (int): Custom attribute representing the position of the tick in a sequence.
"""
time: float
bid: float
ask: float
last: float
volume: float
time_msc: float
flags: TickFlag
volume_real: float
class BookInfo(Base):
"""Book Information Class.
+46 -23
View File
@@ -1,5 +1,6 @@
from typing import TypeDict
import pickle
import random
import lzma
from datetime import datetime
from logging import getLogger
import asyncio
@@ -7,21 +8,31 @@ import asyncio
import pytz
from MetaTrader5 import Tick, SymbolInfo
import pandas as pd
from pandas import DataFrame
from ...core.meta_trader import MetaTrader
from ...core.config import Config
from ...core.errors import Error
from ...core.constants import TimeFrame, CopyTicks, OrderType
from ...core.models import (AccountInfo, SymbolInfo, BookInfo, TradeOrder, OrderCheckResult, OrderSendResult,
TradePosition, TradeDeal)
TradePosition, TradeDeal, TickInfo)
from ...utils import backoff_decorator
logger = getLogger(__name__)
class Data(TypeDict):
account: AccountInfo
symbols: dict[str, SymbolInfo]
prices: DataFrame
ticks: DataFrame
rates: DataFrame
span: range
class GetData(MetaTrader):
config: Config = Config()
def __init__(self, start: datetime, end: datetime, timeframes: set[TimeFrame], symbols: set[str],
def __init__(self, *, start: datetime, end: datetime, timeframes: set[TimeFrame], symbols: set[str],
interval: int = 60, name: str = '', tz: str = 'Etc/UTC'):
""""""
super().__init__()
@@ -37,7 +48,7 @@ class GetData(MetaTrader):
self.span = range(start := int(self.start.timestamp()), diff + start)
self.mt5 = MetaTrader()
async def get_test_data(self) -> dict:
async def get_data(self) -> Data:
""""""
data = {}
rates, ticks, prices = await asyncio.gather(self.get_symbols_rates(), self.get_symbols_ticks(),
@@ -48,43 +59,55 @@ class GetData(MetaTrader):
data['prices'] = prices
data['symbols'] = await self.get_symbols_info()
data['account'] = self.get_account_info()
data['range'] = self.span
return data
async def get_and_save_data(self) -> None:
async def pickle_data(self) -> None:
""""""
data = await self.get_test_data()
data = await self.get_data()
fh = open(f'{self.config.root}/data/{self.name}', 'wb')
pickle.dump(data, fh)
fh.close()
def load_data(self, name: str = '') -> dict:
async def compress_data(self):
""""""
name = name or self.name
file = open(f'{self.config.root}/data/{name}', 'rb')
data = pickle.load(file)
file.close()
data = await self.get_data()
bdata = pickle.dumps(data)
name = self.name + 'xz'
with lzma.open(name, 'w') as fh:
fh.write(bdata)
@classmethod
def load_data(cls, name: str, compressed=False) -> dict:
""""""
fo = open(f'{cls.config.root}/data/{name}', 'rb')
if compressed:
data = lzma.decompress(fo)
data = pickle.load(data)
fo.close()
return data
async def get_symbols_info(self):
async def get_symbols_info(self) -> dict[str, SymbolInfo]:
""""""
tasks = [self.get_symbol_info(symbol) for symbol in self.symbols]
res = await asyncio.gather(*tasks)
return {symbol: info for symbol, info in res}
return {symbol: SymbolInfo(**info) for symbol, info in res}
async def get_symbols_ticks(self):
async def get_symbols_ticks(self) -> dict[str, DataFrame]:
""""""
tasks = [self.get_symbol_ticks(symbol) for symbol in self.symbols]
res = await asyncio.gather(*tasks)
return {symbol: ticks for symbol, ticks in res}
return {symbol: tick for symbol, tick in res}
async def get_symbols_prices(self):
async def get_symbols_prices(self) -> dict[str, DataFrame]:
""""""
tasks = [self.get_symbol_prices(symbol) for symbol in self.symbols]
res = await asyncio.gather(*tasks)
return {symbol: prices for symbol, prices in res}
async def get_symbols_rates(self):
async def get_symbols_rates(self) -> dict[str: dict[TimeFrame: DataFrame]]:
""""""
tasks = [self.get_symbol_rates(symbol, timeframe) for symbol in self.symbols for timeframe in self.timeframes]
res = await asyncio.gather(*tasks)
@@ -94,19 +117,19 @@ class GetData(MetaTrader):
return data
@backoff_decorator(max_retries=5)
async def get_account_info(self) -> AccountInfo | None:
async def get_account_info(self) -> dict:
""""""
res = await self.mt5.account_info()
return res._asdict()
@backoff_decorator(max_retries=5)
async def get_symbol_info(self, symbol: str):
async def get_symbol_info(self, symbol: str) -> tuple[str, dict]:
""""""
res = await self.mt5.symbol_info(symbol)
return symbol, res._asdict()
@backoff_decorator(max_retries=5)
async def get_symbol_ticks(self, symbol: str):
async def get_symbol_ticks(self, symbol: str) -> tuple[str, DataFrame]:
""""""
res = await self.mt5.copy_ticks_range(symbol, self.start, self.end, CopyTicks.ALL)
res = pd.DataFrame(res)
@@ -115,7 +138,7 @@ class GetData(MetaTrader):
return symbol, res
@backoff_decorator(max_retries=5)
async def get_symbol_prices(self, symbol: str):
async def get_symbol_prices(self, symbol: str) -> tuple[str, DataFrame]:
""""""
res = await self.mt5.copy_ticks_range(symbol, self.start, self.end, CopyTicks.ALL)
res = pd.DataFrame(res)
@@ -125,7 +148,7 @@ class GetData(MetaTrader):
return symbol, res
@backoff_decorator(max_retries=5)
async def get_symbol_rates(self, symbol: str, timeframe: TimeFrame):
async def get_symbol_rates(self, symbol: str, timeframe: TimeFrame) -> tuple[str, TimeFrame, DataFrame]:
""""""
res = await self.mt5.copy_rates_range(symbol, timeframe, self.start, self.end)
res = pd.DataFrame(res)
+6 -5
View File
@@ -1,14 +1,15 @@
from typing import Literal
from ...core.models import AccountInfo, SymbolInfo
from typing import Literal, TypedDict
from ...core.models import AccountInfo, SymbolInfo, Tick
from ...core.constants import TimeFrame
from ...core.meta_trader import MetaTrader
# from ...account import Account
from .get_data import Data, GetData
class TestData:
def __init__(self, data):
self._data = data
def __init__(self, data: Data):
self.data = data
self.cursor = 0
def __getitem__(self, item: tuple[Literal['ticks', 'rates'], SymbolInfo, TimeFrame]):
type_, symbol, time_frame = item
+1 -1
View File
@@ -32,7 +32,7 @@ class Tick:
last: float
volume: float
time_msc: float
flags: float
flags: TickFlag
volume_real: float
Index: int
+1
View File
@@ -60,4 +60,5 @@ def backoff_decorator(func=None, *, max_retries: int = 3, retries: int = 0, dela
delay += 1
retries += 1
return await wrapper(*args, **kwargs)
return wrapper