Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/tinkoff/invest/utils.py
7826 views
1
import ast
2
import dataclasses
3
from datetime import datetime, timedelta, timezone
4
from decimal import Decimal
5
from typing import Generator, Tuple
6
7
import dateutil.parser
8
9
from .schemas import CandleInterval, Quotation, SubscriptionInterval
10
11
__all__ = ("get_intervals",)
12
13
DAYS_IN_YEAR = 365
14
15
16
MAX_INTERVALS = {
17
CandleInterval.CANDLE_INTERVAL_1_MIN: timedelta(days=1),
18
CandleInterval.CANDLE_INTERVAL_5_MIN: timedelta(days=1),
19
CandleInterval.CANDLE_INTERVAL_15_MIN: timedelta(days=1),
20
CandleInterval.CANDLE_INTERVAL_HOUR: timedelta(weeks=1),
21
CandleInterval.CANDLE_INTERVAL_DAY: timedelta(days=DAYS_IN_YEAR),
22
}
23
24
25
def get_intervals(
26
interval: CandleInterval, from_: datetime, to: datetime
27
) -> Generator[Tuple[datetime, datetime], None, None]:
28
max_interval = MAX_INTERVALS[interval]
29
local_from = from_
30
interval_timedelta = candle_interval_to_timedelta(interval)
31
while local_from + interval_timedelta <= to:
32
yield local_from, min(local_from + max_interval, to)
33
local_from += max_interval
34
35
36
def quotation_to_decimal(quotation: Quotation) -> Decimal:
37
fractional = quotation.nano / Decimal("10e8")
38
return Decimal(quotation.units) + fractional
39
40
41
def decimal_to_quotation(decimal: Decimal) -> Quotation:
42
fractional = decimal % 1
43
return Quotation(units=int(decimal // 1), nano=int(fractional * Decimal("10e8")))
44
45
46
# fmt: off
47
_CANDLE_INTERVAL_TO_SUBSCRIPTION_INTERVAL_MAPPING = {
48
CandleInterval.CANDLE_INTERVAL_1_MIN:
49
SubscriptionInterval.SUBSCRIPTION_INTERVAL_ONE_MINUTE,
50
CandleInterval.CANDLE_INTERVAL_5_MIN:
51
SubscriptionInterval.SUBSCRIPTION_INTERVAL_FIVE_MINUTES,
52
CandleInterval.CANDLE_INTERVAL_UNSPECIFIED:
53
SubscriptionInterval.SUBSCRIPTION_INTERVAL_UNSPECIFIED,
54
}
55
# fmt: on
56
57
58
def candle_interval_to_subscription_interval(
59
candle_interval: CandleInterval,
60
) -> SubscriptionInterval:
61
return _CANDLE_INTERVAL_TO_SUBSCRIPTION_INTERVAL_MAPPING.get(
62
candle_interval, SubscriptionInterval.SUBSCRIPTION_INTERVAL_UNSPECIFIED
63
)
64
65
66
def now() -> datetime:
67
return datetime.utcnow().replace(tzinfo=timezone.utc)
68
69
70
_CANDLE_INTERVAL_TO_TIMEDELTA_MAPPING = {
71
CandleInterval.CANDLE_INTERVAL_1_MIN: timedelta(minutes=1),
72
CandleInterval.CANDLE_INTERVAL_5_MIN: timedelta(minutes=5),
73
CandleInterval.CANDLE_INTERVAL_15_MIN: timedelta(minutes=15),
74
CandleInterval.CANDLE_INTERVAL_HOUR: timedelta(hours=1),
75
CandleInterval.CANDLE_INTERVAL_DAY: timedelta(days=1),
76
CandleInterval.CANDLE_INTERVAL_UNSPECIFIED: timedelta(minutes=1),
77
}
78
79
80
def candle_interval_to_timedelta(candle_interval: CandleInterval) -> timedelta:
81
if delta := _CANDLE_INTERVAL_TO_TIMEDELTA_MAPPING.get(candle_interval):
82
return delta
83
raise ValueError(f"Cannot convert {candle_interval} to timedelta")
84
85
86
_DATETIME_MIN = datetime.min.replace(tzinfo=timezone.utc)
87
88
89
def ceil_datetime(datetime_: datetime, delta: timedelta):
90
return datetime_ + (_DATETIME_MIN - datetime_) % delta
91
92
93
def floor_datetime(datetime_: datetime, delta: timedelta):
94
return datetime_ - (datetime_ - _DATETIME_MIN) % delta
95
96
97
def dataclass_from_dict(klass, d):
98
if issubclass(int, klass):
99
return int(d)
100
if issubclass(bool, klass):
101
return bool(d)
102
if issubclass(klass, datetime):
103
return dateutil.parser.parse(d).replace(tzinfo=timezone.utc)
104
if issubclass(klass, Quotation):
105
d = ast.literal_eval(d)
106
fieldtypes = {f.name: f.type for f in dataclasses.fields(klass)}
107
return klass(**{f: dataclass_from_dict(fieldtypes[f], d[f]) for f in d})
108
109
110
def datetime_range_floor(
111
date_range: Tuple[datetime, datetime]
112
) -> Tuple[datetime, datetime]:
113
start, end = date_range
114
return start.replace(second=0, microsecond=0), end.replace(second=0, microsecond=0)
115
116