mirror of
https://github.com/Ichinga-Samuel/aiomql.git
synced 2026-08-05 16:27:44 +00:00
4.0.15dev
This commit is contained in:
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "aiomql"
|
||||
version = "4.0.15b"
|
||||
version = "4.0.15dev"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
classifiers = [
|
||||
|
||||
@@ -3,5 +3,4 @@ from .candle_patterns import *
|
||||
from .symbols import *
|
||||
from .utils import *
|
||||
from .traders import *
|
||||
from .quants import *
|
||||
from .trackers import *
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from aiomql import Candle, Candles
|
||||
|
||||
from ..quants.change import percentage_difference
|
||||
from ...utils.change import percentage_difference
|
||||
|
||||
|
||||
def is_bullish_fractal(candles: Candles) -> tuple[bool, Candle|None]:
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from .change import *
|
||||
@@ -6,7 +6,7 @@ from ...lib import Symbol, Positions, Order
|
||||
from ...core.models import TradePosition, TradeAction, OrderSendResult
|
||||
from ...core.constants import OrderType
|
||||
from ...core.config import Config
|
||||
from ..quants import percentage_increase, percentage_decrease
|
||||
from ...utils.change import percentage_increase, percentage_decrease
|
||||
from .position_tracker import PositionTracker
|
||||
|
||||
logger = getLogger()
|
||||
@@ -54,26 +54,38 @@ class OpenPosition:
|
||||
await self.update_position()
|
||||
if not self.is_open:
|
||||
self.remove_from_state()
|
||||
await self.close_pending_order()
|
||||
except Exception as exe:
|
||||
logger.error("%s: Unable to remove closed position from state", exe)
|
||||
|
||||
async def close_pending_order(self) -> tuple[bool, OrderSendResult | None]:
|
||||
try:
|
||||
if self.pending_hedge:
|
||||
res = await Order.cancel_order(order=self.pending_hedge.order, symbol=self.symbol.name)
|
||||
if res.retcode != 10009:
|
||||
logger.critical("%s: Unable to cancel pending order", res.comment)
|
||||
return False, res
|
||||
self.pending_hedge = None
|
||||
return True, res
|
||||
except Exception as exe:
|
||||
logger.error("%s: Unable to cancel pending order", exe)
|
||||
return False, None
|
||||
|
||||
async def update_position(self) -> bool:
|
||||
# ToDo: remove pending order
|
||||
pos = await self.positions.get_position_by_ticket(ticket=self.ticket)
|
||||
if pos is not None:
|
||||
self.position = pos
|
||||
self.is_open = True
|
||||
else:
|
||||
self.is_open = False
|
||||
await self.close_pending_order()
|
||||
return self.is_open
|
||||
|
||||
async def modify_stops(self, *, sl: float = None, tp: float = None,
|
||||
use_stop_levels=False) -> tuple[bool, OrderSendResult | None]:
|
||||
try:
|
||||
# todo: add stops
|
||||
tick = await self.symbol.info_tick()
|
||||
|
||||
# modify stop_loss
|
||||
if sl is not None and use_stop_levels is True:
|
||||
min_stops_value = (self.symbol.trade_stops_level + self.symbol.spread) * self.symbol.point
|
||||
if self.position.type == OrderType.BUY:
|
||||
@@ -149,8 +161,8 @@ class OpenPosition:
|
||||
logger.error("%s: Error occurred in track method of Open Position for %d:%s",
|
||||
exe, self.symbol.name, self.ticket)
|
||||
|
||||
async def profit_to_price(self, profit):
|
||||
action = OrderType.BUY if self.position.type == 0 else OrderType.SELL
|
||||
async def profit_to_price(self, *, profit):
|
||||
action = self.position.type
|
||||
volume = self.position.volume
|
||||
price_open = self.position.price_open
|
||||
price_close = percentage_increase(price_open, 50) if action == 0 else percentage_decrease(price_open, 50)
|
||||
|
||||
@@ -2,7 +2,7 @@ from logging import getLogger
|
||||
|
||||
|
||||
from .open_position import OpenPosition
|
||||
from ..quants import extend_interval_by_percentage, get_percentage_position, percentage_position
|
||||
from ...utils.change import extend_interval_by_percentage, get_percentage_position, percentage_position
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
@@ -56,7 +56,7 @@ async def exit_at_checkpoint(pos: OpenPosition, /, start: float = 80, trail: flo
|
||||
if is_open is False:
|
||||
return
|
||||
position = pos.position
|
||||
if position.profit > 0 and percentage_position(position.price_open, position.tp, position.price_current) >= start:
|
||||
if percentage_position(position.price_open, position.tp, position.price_current) >= start:
|
||||
new_checkpoint = get_percentage_position(position.price_open, position.price_current, 100-trail)
|
||||
change_checkpoint = False
|
||||
if position.type.long and new_checkpoint > (pos.checkpoint or position.price_open):
|
||||
@@ -66,6 +66,7 @@ async def exit_at_checkpoint(pos: OpenPosition, /, start: float = 80, trail: flo
|
||||
if change_checkpoint:
|
||||
pos.checkpoint = new_checkpoint
|
||||
pos.use_checkpoint = True
|
||||
await pos.modify_stops(sl=new_checkpoint, use_stop_levels=True)
|
||||
logger.info("New checkpoint created for %s:%d at %f:%f",
|
||||
position.symbol, position.ticket, new_checkpoint, position.profit)
|
||||
close = False
|
||||
|
||||
@@ -119,15 +119,13 @@ class Base:
|
||||
Returns:
|
||||
dict: A dictionary of instance and class attributes
|
||||
"""
|
||||
try:
|
||||
_filter = self.exclude.difference(self.include)
|
||||
return {
|
||||
key: value
|
||||
for key, value in (self.class_vars | self.__dict__).items()
|
||||
if key not in _filter and value is not None
|
||||
}
|
||||
except Exception as err:
|
||||
logger.warning(err)
|
||||
_filter = self.exclude.difference(self.include)
|
||||
return {
|
||||
key: value
|
||||
for key, value in (self.class_vars | self.__dict__).items()
|
||||
if key not in _filter and value is not None
|
||||
}
|
||||
|
||||
|
||||
|
||||
class _Base(Base):
|
||||
|
||||
@@ -86,7 +86,7 @@ class Bot:
|
||||
logger.info("Login Successful")
|
||||
await self.init_strategies()
|
||||
self.add_coroutine(coroutine=self.config.task_queue.run, on_separate_thread=True)
|
||||
self.add_coroutine(coroutine=self.executor.exit)
|
||||
self.add_function(function=self.executor.exit)
|
||||
|
||||
if len(self.executor.strategy_runners) == 0:
|
||||
logger.warning("No strategies were added to the bot. Exiting in one second")
|
||||
@@ -112,7 +112,7 @@ class Bot:
|
||||
logger.info("Login Successful")
|
||||
self.init_strategies_sync()
|
||||
self.add_coroutine(coroutine=self.config.task_queue.run, on_separate_thread=True)
|
||||
self.add_coroutine(coroutine=self.executor.exit)
|
||||
self.add_function(function=self.executor.exit)
|
||||
|
||||
if len(self.executor.strategy_runners) == 0:
|
||||
logger.warning("No strategies were added to the bot. Exiting in one second")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import asyncio
|
||||
import os
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from signal import signal, SIGINT
|
||||
from typing import Coroutine, Callable
|
||||
@@ -93,16 +94,16 @@ class Executor:
|
||||
def sigint_handle(self, signum, frame):
|
||||
self.config.shutdown = True
|
||||
|
||||
async def exit(self):
|
||||
def exit(self):
|
||||
"""Shutdown the executor"""
|
||||
start = asyncio.get_event_loop().time()
|
||||
start = time.time()
|
||||
try:
|
||||
while self.config.shutdown is False and self.config.force_shutdown is False:
|
||||
if self.timeout is not None and self.timeout < (asyncio.get_event_loop().time() - start):
|
||||
if self.timeout is not None and self.timeout < (time.time() - start):
|
||||
self.config.shutdown = True
|
||||
break
|
||||
timeout = self.timeout or 1
|
||||
await asyncio.sleep(timeout)
|
||||
time.sleep(timeout)
|
||||
for strategy in self.strategy_runners:
|
||||
strategy.running = False
|
||||
self.config.task_queue.cancel()
|
||||
|
||||
@@ -32,12 +32,11 @@ class History:
|
||||
group: str
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
instance = super().__new__(cls)
|
||||
if not hasattr(instance.__class__, 'config'):
|
||||
instance.__class__.config = Config()
|
||||
if not hasattr(instance.__class__, 'mt5'):
|
||||
instance.__class__.mt5 = MetaTrader() if instance.config.mode != "backtest" else MetaBackTester()
|
||||
return instance
|
||||
if not hasattr(cls, 'config'):
|
||||
cls.config = Config()
|
||||
if not hasattr(cls, 'mt5'):
|
||||
cls.mt5 = MetaTrader() if cls.config.mode != "backtest" else MetaBackTester()
|
||||
return super().__new__(cls)
|
||||
|
||||
def __init__(
|
||||
self, *, date_from: datetime | float, date_to: datetime | float, group: str = "", use_utc: bool = float
|
||||
|
||||
+11
-2
@@ -1,10 +1,10 @@
|
||||
from logging import getLogger
|
||||
|
||||
from ..core.models import TradeRequest, TradeOrder, OrderCheckResult, OrderSendResult
|
||||
from ..core.constants import TradeAction, OrderTime, OrderFilling
|
||||
from ..core.constants import TradeAction, OrderTime, OrderFilling, OrderType
|
||||
from ..core.exceptions import OrderError
|
||||
from ..core.base import _Base
|
||||
from ..utils import error_handler
|
||||
from ..utils import error_handler, percentage_decrease, percentage_increase
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
@@ -152,3 +152,12 @@ class Order(_Base, TradeRequest):
|
||||
def request(self) -> dict:
|
||||
"""Return the order request as a dictionary."""
|
||||
return {key: value for key, value in self.dict.items() if key in self.mt5.TradeRequest.__match_args__}
|
||||
|
||||
@classmethod
|
||||
async def profit_to_price(cls, *, profit: float, order_type: OrderType, volume: float, symbol: str, price_open: float):
|
||||
price_close = percentage_increase(price_open, 50) if order_type == 0 else percentage_decrease(price_open, 50)
|
||||
half_profit = await cls.mt5.order_calc_profit(symbol=symbol, action=order_type, volume=volume,
|
||||
price_open=price_open, price_close=price_close)
|
||||
rate = profit / half_profit * 50
|
||||
rate = percentage_increase(price_open, rate) if order_type == 0 else percentage_decrease(price_open, rate)
|
||||
return rate
|
||||
|
||||
@@ -71,7 +71,7 @@ class Positions:
|
||||
kwargs["group"] = group
|
||||
positions = await cls.mt5.positions_get(**kwargs)
|
||||
if positions is not None:
|
||||
return cls.positions
|
||||
return tuple(TradePosition(**pos._asdict()) for pos in positions)
|
||||
logger.warning("Failed to get open positions")
|
||||
return ()
|
||||
|
||||
|
||||
+36
-3
@@ -41,6 +41,20 @@ class RAM:
|
||||
"""
|
||||
[setattr(self, key, value) for key, value in kwargs.items()]
|
||||
|
||||
def get_amount_sync(self) -> float:
|
||||
"""Calculate the amount to risk per trade as a percentage of margin_free.
|
||||
|
||||
Returns:
|
||||
float: Amount to risk per trade
|
||||
"""
|
||||
if self.fixed_amount:
|
||||
return self.fixed_amount
|
||||
self.account.refresh_sync()
|
||||
amount = self.account.margin_free * (self.risk / 100)
|
||||
if self.min_amount and self.max_amount:
|
||||
return max(self.min_amount, min(self.max_amount, amount))
|
||||
return amount
|
||||
|
||||
async def get_amount(self) -> float:
|
||||
"""Calculate the amount to risk per trade as a percentage of margin_free.
|
||||
|
||||
@@ -61,8 +75,8 @@ class RAM:
|
||||
Returns:
|
||||
bool: True if the number of losing positions is less than or equal the loss limit
|
||||
"""
|
||||
positions = await self.positions.get_positions()
|
||||
loosing = [position for position in positions if position.profit < 0]
|
||||
positions = await self.account.mt5.positions_get()
|
||||
loosing = [position for position in positions if position.profit <= 0]
|
||||
return len(loosing) <= self.loss_limit
|
||||
|
||||
async def check_open_positions(self) -> bool:
|
||||
@@ -71,5 +85,24 @@ class RAM:
|
||||
Returns:
|
||||
bool: True if the number of open positions is less than the open limit
|
||||
"""
|
||||
positions = await self.positions.get_positions()
|
||||
positions = await self.account.mt5.positions_get()
|
||||
return len(positions) <= self.open_limit
|
||||
|
||||
def check_losing_positions_sync(self) -> bool:
|
||||
"""Check if the number of losing positions is less than the loss limit
|
||||
|
||||
Returns:
|
||||
bool: True if the number of losing positions is less than or equal the loss limit
|
||||
"""
|
||||
positions = self.account.mt5._positions_get()
|
||||
loosing = [position for position in positions if position.profit <= 0]
|
||||
return len(loosing) <= self.loss_limit
|
||||
|
||||
def check_open_positions_sync(self) -> bool:
|
||||
"""Check if the number of open positions is less than or equal the loss limit.
|
||||
|
||||
Returns:
|
||||
bool: True if the number of open positions is less than the open limit
|
||||
"""
|
||||
positions = self.account.mt5._positions_get()
|
||||
return len(positions) <= self.open_limit
|
||||
|
||||
@@ -61,15 +61,32 @@ class Result:
|
||||
with self.lock:
|
||||
trade_record_mode = trade_record_mode or self.config.trade_record_mode
|
||||
if trade_record_mode == "csv":
|
||||
await self.to_csv()
|
||||
self.to_csv()
|
||||
elif trade_record_mode == "json":
|
||||
await self.to_json()
|
||||
self.to_json()
|
||||
elif trade_record_mode == "sql":
|
||||
self.to_sql()
|
||||
else:
|
||||
logger.error(f"Invalid trade record mode: {trade_record_mode}")
|
||||
|
||||
async def to_csv(self):
|
||||
def save_sync(self, *, trade_record_mode: Literal["csv", "json"] = None):
|
||||
"""Record trade results as a csv or json file
|
||||
|
||||
Args:
|
||||
trade_record_mode (Literal['csv'|'json']): Mode of saving trade records
|
||||
"""
|
||||
with self.lock:
|
||||
trade_record_mode = trade_record_mode or self.config.trade_record_mode
|
||||
if trade_record_mode == "csv":
|
||||
self.to_csv()
|
||||
elif trade_record_mode == "json":
|
||||
self.to_json()
|
||||
elif trade_record_mode == "sql":
|
||||
self.to_sql()
|
||||
else:
|
||||
logger.error(f"Invalid trade record mode: {trade_record_mode}")
|
||||
|
||||
def to_csv(self):
|
||||
"""Record trade results and associated parameters as a csv file"""
|
||||
try:
|
||||
data = self.get_data()
|
||||
@@ -99,7 +116,7 @@ class Result:
|
||||
logger.error("%s: Unable to serialize value", err)
|
||||
return ""
|
||||
|
||||
async def to_json(self):
|
||||
def to_json(self):
|
||||
"""Save trades and strategy parameters in a json file"""
|
||||
try:
|
||||
file = self.config.records_dir / f"{self.name}.json"
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
from typing import ClassVar
|
||||
from datetime import datetime, UTC
|
||||
from logging import getLogger
|
||||
|
||||
from ...core.config import Config
|
||||
from ...core.sync.meta_trader import MetaTrader
|
||||
from ...core.models import TradeDeal, TradeOrder
|
||||
from ...core.meta_backtester import MetaBackTester
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class History:
|
||||
"""The history class handles completed trade deals and trade orders in the trading history of an account.
|
||||
|
||||
Attributes:
|
||||
deals (list[TradeDeal]): Iterable of trade deals
|
||||
orders (list[TradeOrder]): Iterable of trade orders
|
||||
total_deals: Total number of deals
|
||||
total_orders (int): Total number orders
|
||||
group (str): Filter for selecting history by symbols.
|
||||
mt5 (MetaTrader): MetaTrader instance
|
||||
config (Config): Config instance
|
||||
"""
|
||||
mt5: ClassVar[MetaTrader | MetaBackTester]
|
||||
config: ClassVar[Config]
|
||||
deals: tuple[TradeDeal, ...]
|
||||
orders: tuple[TradeOrder, ...]
|
||||
total_deals: int
|
||||
total_orders: int
|
||||
group: str
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if not hasattr(cls, 'config'):
|
||||
cls.config = Config()
|
||||
if not hasattr(cls, 'mt5'):
|
||||
cls.mt5 = MetaTrader() if cls.config.mode != "backtest" else MetaBackTester()
|
||||
return super().__new__(cls)
|
||||
|
||||
def __init__(
|
||||
self, *, date_from: datetime | float, date_to: datetime | float, group: str = "", use_utc: bool = float
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
date_from (datetime, float): Date the orders are requested from. Set by the 'datetime' object or as a
|
||||
number of seconds elapsed since 1970.01.01.
|
||||
|
||||
date_to (datetime, float): Date up to which the orders are requested. Set by the 'datetime' object or as a
|
||||
number of seconds elapsed since 1970.01.01.
|
||||
|
||||
use_utc (bool): Convert date_from and date_to to UTC. Default is False.
|
||||
|
||||
group (str): Filter for selecting history by symbols. This defaults to an empty string
|
||||
"""
|
||||
date_from = date_from if isinstance(date_from, datetime) else datetime.fromtimestamp(date_from)
|
||||
date_to = date_to if isinstance(date_to, datetime) else datetime.fromtimestamp(date_to)
|
||||
self.date_from = date_from.astimezone(UTC) if use_utc else date_from
|
||||
self.date_to = date_to.astimezone(UTC) if use_utc else date_to
|
||||
self.group = group
|
||||
self.deals: tuple[TradeDeal, ...] = ()
|
||||
self.orders: tuple[TradeOrder, ...] = ()
|
||||
self.total_deals: int = 0
|
||||
self.total_orders: int = 0
|
||||
|
||||
def initialize(self):
|
||||
"""Get history deals and orders"""
|
||||
deals, orders = [self.get_deals(), self.get_orders()]
|
||||
self.deals = deals if isinstance(deals, tuple) else ()
|
||||
self.orders = orders if isinstance(orders, tuple) else ()
|
||||
self.total_deals = len(self.deals)
|
||||
self.total_orders = len(self.orders)
|
||||
|
||||
def get_deals(self) -> tuple[TradeDeal, ...]:
|
||||
"""Get deals from trading history using the parameters set in the constructor.
|
||||
|
||||
Returns:
|
||||
tuple[TradeDeal, ...]: A list of trade deals
|
||||
"""
|
||||
deals = self.mt5.history_deals_get(date_from=self.date_from, date_to=self.date_to, group=self.group)
|
||||
if deals is not None:
|
||||
return tuple(TradeDeal(**deal._asdict()) for deal in deals)
|
||||
logger.warning(f"Failed to get deals")
|
||||
return tuple()
|
||||
|
||||
def get_deals_by_ticket(self, *, ticket: int) -> tuple[TradeDeal, ...]:
|
||||
"""Call specifying the order ticket. Return all deals having the specified order ticket in the DEAL_ORDER
|
||||
property.
|
||||
|
||||
Args:
|
||||
ticket (int): The order ticket
|
||||
|
||||
Returns:
|
||||
tuple[TradeDeal]: A tuple of all deals with the order ticket
|
||||
"""
|
||||
return tuple(sorted((deal for deal in self.deals if deal.order == ticket), key=lambda x: x.time_msc))
|
||||
|
||||
def get_deals_by_position(self, *, position: int = None) -> tuple[TradeDeal, ...]:
|
||||
"""
|
||||
Get all deals with the specified position ticket in the DEAL_POSITION_ID property
|
||||
Args:
|
||||
position (int): The position ticket
|
||||
|
||||
Returns:
|
||||
tuple[TradeDeal]: A tuple of all deals with the position ticket
|
||||
"""
|
||||
return tuple(sorted((deal for deal in self.deals if deal.position_id == position), key=lambda x: x.time_msc))
|
||||
|
||||
def get_orders(self) -> tuple[TradeOrder, ...]:
|
||||
"""Get orders from trading history using the parameters set in the constructor or the method arguments.
|
||||
|
||||
Returns:
|
||||
list[TradeOrder]: A list of trade orders
|
||||
"""
|
||||
orders = self.mt5.history_orders_get(date_from=self.date_from, date_to=self.date_to, group=self.group)
|
||||
|
||||
if orders is not None:
|
||||
return tuple(TradeOrder(**order._asdict()) for order in orders)
|
||||
|
||||
logger.warning(f"Failed to get orders")
|
||||
return tuple()
|
||||
|
||||
def get_orders_by_ticket(self, *, ticket: int) -> tuple[TradeOrder, ...]:
|
||||
"""filter orders by ticket"""
|
||||
return tuple(sorted((order for order in self.orders if order.ticket == ticket), key=lambda x: x.time_done_msc))
|
||||
|
||||
def get_orders_by_position(self, *, position: int) -> tuple[TradeOrder, ...]:
|
||||
"""filter orders by position"""
|
||||
return tuple(
|
||||
sorted((order for order in self.orders if order.position_id == position), key=lambda x: x.time_done_msc)
|
||||
)
|
||||
@@ -48,6 +48,12 @@ class Order(_Base, TradeRequest):
|
||||
"""
|
||||
return cls.mt5.orders_total()
|
||||
|
||||
@classmethod
|
||||
def cancel_order(cls, *, order: int, symbol: str) -> OrderSendResult:
|
||||
"""Cancel an active pending order by ticket number."""
|
||||
res = cls.mt5.order_send({"symbol": symbol, "order": order, "action": TradeAction.REMOVE})
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def get_pending_order(cls, *, ticket: int) -> TradeOrder | None:
|
||||
"""
|
||||
|
||||
@@ -69,7 +69,7 @@ class Positions:
|
||||
kwargs["group"] = group
|
||||
positions = cls.mt5.positions_get(**kwargs)
|
||||
if positions is not None:
|
||||
return cls.positions
|
||||
return tuple(TradePosition(**pos._asdict()) for pos in positions)
|
||||
logger.warning("Failed to get open positions")
|
||||
return ()
|
||||
|
||||
|
||||
@@ -7,11 +7,10 @@ import csv
|
||||
import logging
|
||||
from typing import Iterable
|
||||
|
||||
from MetaTrader5 import TradePosition
|
||||
|
||||
from ..core.config import Config
|
||||
from ..core.meta_trader import MetaTrader
|
||||
from ..core.meta_backtester import MetaBackTester
|
||||
from ..core.models import TradePosition
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ from datetime import datetime, UTC
|
||||
from typing import TypeVar
|
||||
from logging import getLogger
|
||||
|
||||
|
||||
from ..core.models import OrderType, OrderSendResult, OrderCheckResult
|
||||
from ..core.config import Config
|
||||
from ..core.task_queue import QueueItem
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
from .utils import *
|
||||
from .process_pool import *
|
||||
from .change import *
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# from importlib.metadata import version
|
||||
# version = version("pandas-ta")
|
||||
|
||||
from pandas_ta.maps import EXCHANGE_TZ, RATE, Category, Imports
|
||||
from pandas_ta.utils import *
|
||||
from pandas_ta.utils import __all__ as utils_all
|
||||
@@ -42,7 +38,6 @@ __all__ = [
|
||||
"RATE",
|
||||
"Category",
|
||||
"Imports",
|
||||
# "version",
|
||||
"ma",
|
||||
"create_dir",
|
||||
"import_dir",
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# #-*- coding: utf-8 -*-
|
||||
# from pandas_ta import version
|
||||
#
|
||||
# SUPPORT="http://www.pandas-ta.dev/support"
|
||||
#
|
||||
# if __name__ == "__main__":
|
||||
# print(f"Pandas TA: {version}\nSupport: {SUPPORT}")
|
||||
+28
-42
@@ -1,17 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pathlib import Path
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
Iterable,
|
||||
List,
|
||||
Optional,
|
||||
Sequence,
|
||||
TextIO,
|
||||
Tuple,
|
||||
TypeVar,
|
||||
Union
|
||||
)
|
||||
from typing import Any, Iterable, Sequence, TypeVar, Dict, List, Tuple, TextIO, Union, Optional
|
||||
|
||||
from numpy import ndarray, recarray, void
|
||||
from numpy import bool_ as np_bool_
|
||||
@@ -21,40 +9,38 @@ from numpy import integer as np_integer
|
||||
from numpy import number as np_number
|
||||
from pandas import DataFrame, Series
|
||||
|
||||
|
||||
|
||||
# Generic types
|
||||
T = TypeVar("T")
|
||||
|
||||
# Scalars
|
||||
Scalar = Union[str, float, int, complex, bool, object, np_generic]
|
||||
Number = Union[int, float, complex, np_number, np_bool_]
|
||||
Int = Union[int, np_integer]
|
||||
Float = Union[float, np_floating]
|
||||
IntFloat = Union[Int, Float]
|
||||
Scalar = str | float | int | complex | bool | object | np_generic
|
||||
Number = int | float | complex | np_number | np_bool_
|
||||
Int = int | np_integer
|
||||
Float = float | np_floating
|
||||
IntFloat = Int | Float
|
||||
|
||||
# Basic sequences
|
||||
MaybeTuple = Union[T, Tuple[T, ...]]
|
||||
MaybeList = Union[T, List[T]]
|
||||
TupleList = Union[List[T], Tuple[T, ...]]
|
||||
MaybeTupleList = Union[T, List[T], Tuple[T, ...]]
|
||||
MaybeIterable = Union[T, Iterable[T]]
|
||||
MaybeSequence = Union[T, Sequence[T]]
|
||||
ListStr = List[str]
|
||||
MaybeTuple = T | tuple[T, ...]
|
||||
MaybeList = T | list[T]
|
||||
TupleList = list[T] | tuple[T, ...]
|
||||
MaybeTupleList = T | list[T] | tuple[T, ...]
|
||||
MaybeIterable = T | Iterable[T]
|
||||
MaybeSequence = T | Sequence[T]
|
||||
ListStr = list[str]
|
||||
|
||||
DictLike = Union[None, dict]
|
||||
DictLike = None | dict
|
||||
DictLikeSequence = MaybeSequence[DictLike]
|
||||
Args = Tuple[Any, ...]
|
||||
ArgsLike = Union[None, Args]
|
||||
Kwargs = Dict[str, Any]
|
||||
KwargsLike = Union[None, Kwargs]
|
||||
Args = tuple[Any, ...]
|
||||
ArgsLike = None | Args
|
||||
Kwargs = dict[str, Any]
|
||||
KwargsLike = None | Kwargs
|
||||
KwargsLikeSequence = MaybeSequence[KwargsLike]
|
||||
FileName = Union[str, Path]
|
||||
FileName = str | Path
|
||||
|
||||
DTypeLike = Any
|
||||
PandasDTypeLike = Any
|
||||
Shape = Tuple[int, ...]
|
||||
RelaxedShape = Union[int, Shape]
|
||||
Shape = tuple[int, ...]
|
||||
RelaxedShape = int | Shape
|
||||
Array = ndarray
|
||||
Array1d = ndarray
|
||||
Array2d = ndarray
|
||||
@@ -62,10 +48,10 @@ Array3d = ndarray
|
||||
Record = void
|
||||
RecordArray = ndarray
|
||||
RecArray = recarray
|
||||
MaybeArray = Union[T, Array]
|
||||
SeriesFrame = Union[Series, DataFrame]
|
||||
MaybeSeries = Union[T, Series]
|
||||
MaybeSeriesFrame = Union[T, Series, DataFrame]
|
||||
AnyArray = Union[Array, Series, DataFrame]
|
||||
AnyArray1d = Union[Array1d, Series]
|
||||
AnyArray2d = Union[Array2d, DataFrame]
|
||||
MaybeArray = T | Array
|
||||
SeriesFrame = Series | DataFrame
|
||||
MaybeSeries = T | Series
|
||||
MaybeSeriesFrame = T | Series | DataFrame
|
||||
AnyArray = Array | Series | DataFrame
|
||||
AnyArray1d = Array1d | Series
|
||||
AnyArray2d = Array2d | DataFrame
|
||||
|
||||
Reference in New Issue
Block a user