mms-client 1.1.0__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mms_client-1.1.0 → mms_client-1.3.0}/PKG-INFO +2 -1
- {mms_client-1.1.0 → mms_client-1.3.0}/README.md +1 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/pyproject.toml +1 -1
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/services/base.py +18 -6
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/services/market.py +59 -8
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/services/registration.py +2 -0
- mms_client-1.3.0/src/mms_client/types/award.py +310 -0
- mms_client-1.3.0/src/mms_client/types/enums.py +73 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/types/fields.py +73 -2
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/types/market.py +6 -3
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/types/offer.py +3 -31
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/types/resource.py +4 -32
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/types/transport.py +2 -2
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/utils/serialization.py +128 -29
- mms_client-1.1.0/src/mms_client/types/enums.py +0 -26
- {mms_client-1.1.0 → mms_client-1.3.0}/LICENSE +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/__init__.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/client.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/py.typed +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/schemas/wsdl/mi-web-service-jbms.wsdl +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/schemas/wsdl/omi-web-service.wsdl +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/schemas/xsd/mi-market.xsd +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/schemas/xsd/mi-outbnd-reports.xsd +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/schemas/xsd/mi-report.xsd +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/schemas/xsd/mpr.xsd +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/schemas/xsd/omi.xsd +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/security/__init__.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/security/certs.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/security/crypto.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/services/__init__.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/services/omi.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/services/report.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/types/__init__.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/types/base.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/types/registration.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/utils/__init__.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/utils/errors.py +0 -0
- {mms_client-1.1.0 → mms_client-1.3.0}/src/mms_client/utils/web.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mms-client
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: API client for accessing the MMS
|
|
5
5
|
Home-page: https://github.com/ElectroRoute-Japan/mms-client
|
|
6
6
|
Author: Ryan Wood
|
|
@@ -198,6 +198,7 @@ This client is not complete. Currently, it supports the following endpoints:
|
|
|
198
198
|
- MarketSubmit_OfferData
|
|
199
199
|
- MarketQuery_OfferQuery
|
|
200
200
|
- MarketCancel_OfferCancel
|
|
201
|
+
- MarketQuery_AwardResultsQuery
|
|
201
202
|
- RegistrationSubmit_Resource
|
|
202
203
|
- RegistrationQuery_Resource
|
|
203
204
|
|
|
@@ -166,6 +166,7 @@ This client is not complete. Currently, it supports the following endpoints:
|
|
|
166
166
|
- MarketSubmit_OfferData
|
|
167
167
|
- MarketQuery_OfferQuery
|
|
168
168
|
- MarketCancel_OfferCancel
|
|
169
|
+
- MarketQuery_AwardResultsQuery
|
|
169
170
|
- RegistrationSubmit_Resource
|
|
170
171
|
- RegistrationQuery_Resource
|
|
171
172
|
|
|
@@ -10,6 +10,7 @@ from typing import Optional
|
|
|
10
10
|
from typing import Protocol
|
|
11
11
|
from typing import Tuple
|
|
12
12
|
from typing import Type
|
|
13
|
+
from typing import Union
|
|
13
14
|
|
|
14
15
|
from mms_client.security.crypto import Certificate
|
|
15
16
|
from mms_client.security.crypto import CryptoWrapper
|
|
@@ -119,7 +120,7 @@ class ClientProto(Protocol):
|
|
|
119
120
|
def request_many(
|
|
120
121
|
self,
|
|
121
122
|
envelope: E,
|
|
122
|
-
data: P,
|
|
123
|
+
data: Union[P, List[P]],
|
|
123
124
|
config: EndpointConfiguration,
|
|
124
125
|
) -> Tuple[MultiResponse[E, P], Dict[str, bytes]]:
|
|
125
126
|
"""Submit a request to the MMS server and return the multi-response.
|
|
@@ -361,7 +362,7 @@ class BaseClient: # pylint: disable=too-many-instance-attributes
|
|
|
361
362
|
def request_many(
|
|
362
363
|
self,
|
|
363
364
|
envelope: E,
|
|
364
|
-
payload: P,
|
|
365
|
+
payload: Union[P, List[P]],
|
|
365
366
|
config: EndpointConfiguration[E, P],
|
|
366
367
|
) -> Tuple[MultiResponse[E, P], Dict[str, bytes]]:
|
|
367
368
|
"""Submit a request to the MMS server and return the multi-response.
|
|
@@ -374,13 +375,20 @@ class BaseClient: # pylint: disable=too-many-instance-attributes
|
|
|
374
375
|
Returns: The multi-response from the MMS server.
|
|
375
376
|
"""
|
|
376
377
|
# First, create the MMS request from the payload and data.
|
|
378
|
+
is_list = isinstance(payload, list)
|
|
379
|
+
data_type = type(payload[0]) if is_list else type(payload) # type: ignore[index]
|
|
377
380
|
self._logger.debug(
|
|
378
381
|
(
|
|
379
382
|
f"{config.name}: Starting multi-request. Envelope: {type(envelope).__name__}, "
|
|
380
|
-
f"Data: {
|
|
383
|
+
f"Data: {data_type.__name__}"
|
|
381
384
|
),
|
|
382
385
|
)
|
|
383
|
-
|
|
386
|
+
serialized = (
|
|
387
|
+
config.service.serializer.serialize_multi(envelope, payload, data_type) # type: ignore[arg-type]
|
|
388
|
+
if is_list
|
|
389
|
+
else config.service.serializer.serialize(envelope, payload) # type: ignore[type-var]
|
|
390
|
+
)
|
|
391
|
+
request = self._to_mms_request(config.request_type, serialized)
|
|
384
392
|
|
|
385
393
|
# Next, submit the request to the MMS server and get and verify the response.
|
|
386
394
|
resp = self._get_wrapper(config.service).submit(request)
|
|
@@ -391,8 +399,12 @@ class BaseClient: # pylint: disable=too-many-instance-attributes
|
|
|
391
399
|
|
|
392
400
|
# Finally, deserialize and verify the response
|
|
393
401
|
envelope_type = config.response_envelope_type or type(envelope)
|
|
394
|
-
data_type = config.response_data_type or
|
|
395
|
-
data: MultiResponse[E, P] = config.service.serializer.deserialize_multi(
|
|
402
|
+
data_type = config.response_data_type or data_type
|
|
403
|
+
data: MultiResponse[E, P] = config.service.serializer.deserialize_multi(
|
|
404
|
+
resp.payload,
|
|
405
|
+
envelope_type,
|
|
406
|
+
data_type, # type: ignore[arg-type]
|
|
407
|
+
)
|
|
396
408
|
self._verify_multi_response(data, config)
|
|
397
409
|
|
|
398
410
|
# Return the response data and any attachments
|
|
@@ -8,6 +8,8 @@ from mms_client.services.base import ClientProto
|
|
|
8
8
|
from mms_client.services.base import ServiceConfiguration
|
|
9
9
|
from mms_client.services.base import mms_endpoint
|
|
10
10
|
from mms_client.services.base import mms_multi_endpoint
|
|
11
|
+
from mms_client.types.award import AwardQuery
|
|
12
|
+
from mms_client.types.award import AwardResponse
|
|
11
13
|
from mms_client.types.market import MarketCancel
|
|
12
14
|
from mms_client.types.market import MarketQuery
|
|
13
15
|
from mms_client.types.market import MarketSubmit
|
|
@@ -45,7 +47,33 @@ class MarketClientMixin: # pylint: disable=unused-argument
|
|
|
45
47
|
|
|
46
48
|
Returns: The offer that has been registered with the MMS server.
|
|
47
49
|
"""
|
|
48
|
-
#
|
|
50
|
+
# NOTE: The return type does not match the method definition but the decorator will return the correct type
|
|
51
|
+
return MarketSubmit( # type: ignore[return-value]
|
|
52
|
+
date=date or Date.today(),
|
|
53
|
+
participant=self.participant,
|
|
54
|
+
user=self.user,
|
|
55
|
+
market_type=market_type,
|
|
56
|
+
days=days,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
@mms_multi_endpoint("MarketSubmit_OfferData", config, RequestType.INFO, ClientType.BSP)
|
|
60
|
+
def put_offers(
|
|
61
|
+
self: ClientProto, requests: List[OfferData], market_type: MarketType, days: int, date: Optional[Date] = None
|
|
62
|
+
) -> List[OfferData]:
|
|
63
|
+
"""Submit multiple offers to the MMS server.
|
|
64
|
+
|
|
65
|
+
This endpoint is only accessible to BSPs.
|
|
66
|
+
|
|
67
|
+
Arguments:
|
|
68
|
+
requests (List[OfferData]): The offers to submit to the MMS server.
|
|
69
|
+
market_type (MarketType): The type of market for which the offers are being submitted.
|
|
70
|
+
days (int): The number of days ahead for which the offers are being submitted.
|
|
71
|
+
date (Date): The date of the transaction in the format "YYYY-MM-DD". This value defaults to the
|
|
72
|
+
current date.
|
|
73
|
+
|
|
74
|
+
Returns: A list of offers that have been registered with the MMS server.
|
|
75
|
+
"""
|
|
76
|
+
# NOTE: The return type does not match the method definition but the decorator will return the correct type
|
|
49
77
|
return MarketSubmit( # type: ignore[return-value]
|
|
50
78
|
date=date or Date.today(),
|
|
51
79
|
participant=self.participant,
|
|
@@ -57,28 +85,24 @@ class MarketClientMixin: # pylint: disable=unused-argument
|
|
|
57
85
|
@mms_multi_endpoint(
|
|
58
86
|
"MarketQuery_OfferQuery", config, RequestType.INFO, resp_envelope_type=MarketSubmit, resp_data_type=OfferData
|
|
59
87
|
)
|
|
60
|
-
def query_offers(
|
|
61
|
-
self: ClientProto, request: OfferQuery, market_type: MarketType, days: int, date: Optional[Date] = None
|
|
62
|
-
) -> List[OfferData]:
|
|
88
|
+
def query_offers(self: ClientProto, request: OfferQuery, days: int, date: Optional[Date] = None) -> List[OfferData]:
|
|
63
89
|
"""Query the MMS server for offers.
|
|
64
90
|
|
|
65
91
|
This endpoint is accessible to all client types.
|
|
66
92
|
|
|
67
93
|
Arguments:
|
|
68
94
|
request (OfferQuery): The query to submit to the MMS server.
|
|
69
|
-
market_type (MarketType): The type of market for which the offer was submitted.
|
|
70
95
|
days (int): The number of days ahead for which the data is being queried.
|
|
71
96
|
date (Date): The date of the transaction in the format "YYYY-MM-DD". This value defaults to the
|
|
72
97
|
current date.
|
|
73
98
|
|
|
74
99
|
Returns: A list of offers that match the query.
|
|
75
100
|
"""
|
|
76
|
-
#
|
|
101
|
+
# NOTE: The return type does not match the method definition but the decorator will return the correct type
|
|
77
102
|
return MarketQuery( # type: ignore[return-value]
|
|
78
103
|
date=date or Date.today(),
|
|
79
104
|
participant=self.participant,
|
|
80
105
|
user=self.user,
|
|
81
|
-
market_type=market_type,
|
|
82
106
|
days=days,
|
|
83
107
|
)
|
|
84
108
|
|
|
@@ -97,7 +121,7 @@ class MarketClientMixin: # pylint: disable=unused-argument
|
|
|
97
121
|
date (Date): The date of the transaction in the format "YYYY-MM-DD". This value defaults to the
|
|
98
122
|
current date.
|
|
99
123
|
"""
|
|
100
|
-
#
|
|
124
|
+
# NOTE: The return type does not match the method definition but the decorator will return the correct type
|
|
101
125
|
return MarketCancel( # type: ignore[return-value]
|
|
102
126
|
date=date or Date.today(),
|
|
103
127
|
participant=self.participant,
|
|
@@ -105,3 +129,30 @@ class MarketClientMixin: # pylint: disable=unused-argument
|
|
|
105
129
|
market_type=market_type,
|
|
106
130
|
days=days,
|
|
107
131
|
)
|
|
132
|
+
|
|
133
|
+
@mms_endpoint("MarketQuery_AwardResultsQuery", config, RequestType.INFO, resp_data_type=AwardResponse)
|
|
134
|
+
def query_awards(self: ClientProto, request: AwardQuery, days: int, date: Optional[Date] = None) -> AwardResponse:
|
|
135
|
+
"""Query the MMS server for award results.
|
|
136
|
+
|
|
137
|
+
This endpoint is accessible to all client types.
|
|
138
|
+
|
|
139
|
+
If no values are specified for Area, Associated Area, Power Generation Unit Code, or GC Registration Flag,
|
|
140
|
+
the results for all areas will be retrieved. If one or more of these criteria are specified, the results will
|
|
141
|
+
be filtered according to the specified criteria. If no value is specified for the retrieval period, the default
|
|
142
|
+
value for this field is 1.
|
|
143
|
+
|
|
144
|
+
Arguments:
|
|
145
|
+
request (AwardQuery): The query to submit to the MMS server.
|
|
146
|
+
days (int): The number of days ahead for which the data is being queried.
|
|
147
|
+
date (Date): The date of the transaction in the format "YYYY-MM-DD". This value defaults to the
|
|
148
|
+
current date.
|
|
149
|
+
|
|
150
|
+
Returns: The award results that match the query.
|
|
151
|
+
"""
|
|
152
|
+
# NOTE: The return type does not match the method definition but the decorator will return the correct type
|
|
153
|
+
return MarketQuery( # type: ignore[return-value]
|
|
154
|
+
date=date or Date.today(),
|
|
155
|
+
participant=self.participant,
|
|
156
|
+
user=self.user,
|
|
157
|
+
days=days,
|
|
158
|
+
)
|
|
@@ -38,6 +38,7 @@ class RegistrationClientMixin: # pylint: disable=unused-argument
|
|
|
38
38
|
|
|
39
39
|
Returns: The resource that has been registered with the MMS server.
|
|
40
40
|
"""
|
|
41
|
+
# NOTE: The return type does not match the method definition but the decorator will return the correct type
|
|
41
42
|
# For some reason, the registration DTOs require that the participant ID exist on the payload rather than on
|
|
42
43
|
# the envelope so we need to set it before we return the envelope.
|
|
43
44
|
request.participant = self.participant
|
|
@@ -65,6 +66,7 @@ class RegistrationClientMixin: # pylint: disable=unused-argument
|
|
|
65
66
|
|
|
66
67
|
Returns: A list of resources that match the query.
|
|
67
68
|
"""
|
|
69
|
+
# NOTE: The return type does not match the method definition but the decorator will return the correct type
|
|
68
70
|
# For some reason, the registration DTOs require that the participant ID exist on the payload rather than on
|
|
69
71
|
# the envelope so we need to set it before we return the envelope.
|
|
70
72
|
request.participant = self.participant
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""Contains objects for MMS award results."""
|
|
2
|
+
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import List
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from pydantic_core import PydanticUndefined
|
|
9
|
+
from pydantic_extra_types.pendulum_dt import DateTime
|
|
10
|
+
from pydantic_xml import attr
|
|
11
|
+
from pydantic_xml import element
|
|
12
|
+
from pydantic_xml import wrapped
|
|
13
|
+
|
|
14
|
+
from mms_client.types.base import Payload
|
|
15
|
+
from mms_client.types.enums import AreaCode
|
|
16
|
+
from mms_client.types.enums import BooleanFlag
|
|
17
|
+
from mms_client.types.enums import CommandMonitorMethod
|
|
18
|
+
from mms_client.types.enums import ContractResult
|
|
19
|
+
from mms_client.types.enums import Direction
|
|
20
|
+
from mms_client.types.enums import ResourceType
|
|
21
|
+
from mms_client.types.fields import company_short_name
|
|
22
|
+
from mms_client.types.fields import contract_id
|
|
23
|
+
from mms_client.types.fields import dr_patter_number
|
|
24
|
+
from mms_client.types.fields import dr_pattern_name
|
|
25
|
+
from mms_client.types.fields import jbms_id
|
|
26
|
+
from mms_client.types.fields import offer_id
|
|
27
|
+
from mms_client.types.fields import operator_code
|
|
28
|
+
from mms_client.types.fields import participant
|
|
29
|
+
from mms_client.types.fields import power_positive
|
|
30
|
+
from mms_client.types.fields import price
|
|
31
|
+
from mms_client.types.fields import resource_name
|
|
32
|
+
from mms_client.types.fields import resource_short_name
|
|
33
|
+
from mms_client.types.fields import system_code
|
|
34
|
+
from mms_client.types.market import MarketType
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def baseload_file_name(alias: str, optional: bool = False):
|
|
38
|
+
"""Create a field for a baseload file name.
|
|
39
|
+
|
|
40
|
+
Arguments:
|
|
41
|
+
alias (str): The name of the alias to assign to the Pydanitc field. This value will be used to map the field
|
|
42
|
+
to the JSON/XML key.
|
|
43
|
+
optional (bool): If True, the field will be optional with a default of None. If False, the field will be
|
|
44
|
+
required, with no default.
|
|
45
|
+
|
|
46
|
+
Returns: A Pydantic Field object for the baseload file name.
|
|
47
|
+
"""
|
|
48
|
+
return attr(
|
|
49
|
+
default=None if optional else PydanticUndefined,
|
|
50
|
+
name=alias,
|
|
51
|
+
min_length=31,
|
|
52
|
+
max_length=40,
|
|
53
|
+
pattern=r"^W9_[0-9]{4}_[0-9]{8}_[0-9]{2}_[A-Z0-9]{5}_[A-Z0-9_\-]{1,10}\.xml$",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class SubRequirement(Enum):
|
|
58
|
+
"""Commodity combination categories."""
|
|
59
|
+
|
|
60
|
+
PRIMARY = "PRI"
|
|
61
|
+
SECONDARY_1 = "SEC1"
|
|
62
|
+
SECONDARY_2 = "SEC2"
|
|
63
|
+
TERTIARY_1 = "TER1"
|
|
64
|
+
PRIMARY_SECONDARY_1 = "PRI-SEC1"
|
|
65
|
+
PRIMARY_SECONDARY_2 = "PRI-SEC2"
|
|
66
|
+
PRIMARY_TERTIARY_1 = "PRI-TER1"
|
|
67
|
+
SECONDARY = "SEC1-SEC2"
|
|
68
|
+
SECONDARY_1_TERTIARY_1 = "SEC1-TER1"
|
|
69
|
+
SECONDARY_2_TERTIARY_1 = "SEC2-TER1"
|
|
70
|
+
PRIAMRY_SECONDARY = "PRI-SEC1-SEC2"
|
|
71
|
+
PRIMARY_SECONDARY_1_TERTIARY_1 = "PRI-SEC1-TER1"
|
|
72
|
+
PRIMARY_SECONDARY_2_TERTIARY_1 = "PRI-SEC2-TER1"
|
|
73
|
+
SECONDARY_TERTIARY_1 = "SEC1-SEC2-TER1"
|
|
74
|
+
PRIMARY_SECONDARY_TERTIARY_1 = "PRI-SEC1-SEC2-TER1"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ContractSource(Enum):
|
|
78
|
+
"""Describes the source of the contract."""
|
|
79
|
+
|
|
80
|
+
MA = "1"
|
|
81
|
+
SWITCHING = "2"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class AwardQuery(Payload, tag="AwardResultsQuery"):
|
|
85
|
+
"""Query object for bid awards."""
|
|
86
|
+
|
|
87
|
+
# The market for which results should be retrieved
|
|
88
|
+
market_type: MarketType = attr(name="MarketType")
|
|
89
|
+
|
|
90
|
+
# The area for which results should be retrieved. If this isn't provided, then all results will be retrieved
|
|
91
|
+
area: Optional[AreaCode] = attr(default=None, name="Area")
|
|
92
|
+
|
|
93
|
+
# The associated area. If the API user is a BSP, this field cannot be set
|
|
94
|
+
linked_area: Optional[AreaCode] = attr(default=None, name="LinkedArea")
|
|
95
|
+
|
|
96
|
+
# The name of the resource for which results should be retrieved. If this isn't provided, then all results will be
|
|
97
|
+
# retrieved for all resources
|
|
98
|
+
resource: Optional[str] = resource_name("ResourceName", True)
|
|
99
|
+
|
|
100
|
+
# The start date and time for which results should be retrieved. Should conform with the start of a block
|
|
101
|
+
start: DateTime = attr(name="StartTime")
|
|
102
|
+
|
|
103
|
+
# The end date and time for which results should be retrieved. Should conform with the end of a block. You can
|
|
104
|
+
# specify the end date and time of any block within the period from the transaction date to the number of days to
|
|
105
|
+
# get multiple blocks.
|
|
106
|
+
end: DateTime = attr(name="EndTime")
|
|
107
|
+
|
|
108
|
+
# Whether we are before gate close or after gate close. If this isn't provided, then all results will be retrieved
|
|
109
|
+
# regardless of gate closure.
|
|
110
|
+
gate_closed: Optional[BooleanFlag] = attr(default=None, name="AfterGC")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class Award(Payload):
|
|
114
|
+
"""Represents the details of a bid award."""
|
|
115
|
+
|
|
116
|
+
# Unique identifier assigned to the contract
|
|
117
|
+
contract_id: str = contract_id("ContractId")
|
|
118
|
+
|
|
119
|
+
# Unique identifier assigned to the contract by the JBMS
|
|
120
|
+
jbms_id: int = jbms_id("JbmsId")
|
|
121
|
+
|
|
122
|
+
# The area of the power generation unit generating the electricity
|
|
123
|
+
area: AreaCode = attr(name="Area")
|
|
124
|
+
|
|
125
|
+
# The associated area. If the API user is a BSP, it is not set.
|
|
126
|
+
linked_area: Optional[AreaCode] = attr(default=None, name="LinkedArea")
|
|
127
|
+
|
|
128
|
+
# A code identifying the power generation unit for which this bid was awarded
|
|
129
|
+
resource: str = resource_name("ResourceName")
|
|
130
|
+
|
|
131
|
+
# An abbreviated name for the power generation unit for which this bid was awarded
|
|
132
|
+
resource_short_name: str = resource_short_name("ResourceShortName")
|
|
133
|
+
|
|
134
|
+
# The grid code of the resource being traded
|
|
135
|
+
system_code: str = system_code("SystemCode")
|
|
136
|
+
|
|
137
|
+
# How the power generation unit produces electricity
|
|
138
|
+
resource_type: ResourceType = attr(name="ResourceType")
|
|
139
|
+
|
|
140
|
+
# The type of market for which the offer is being submitted. Must be a valid pattern number for the submission date
|
|
141
|
+
# Required for VPP resources. Ensure there are no duplicate pattern numbers for the same resource and start time.
|
|
142
|
+
pattern_number: Optional[int] = dr_patter_number("DrPatternNumber", True)
|
|
143
|
+
|
|
144
|
+
# The name of the list pattern with which this award is associated
|
|
145
|
+
pattern_name: Optional[str] = dr_pattern_name("DrPatternName", True)
|
|
146
|
+
|
|
147
|
+
# The participant ID of the BSP associated with this bid award
|
|
148
|
+
bsp_participant: str = participant("BspParticipantName")
|
|
149
|
+
|
|
150
|
+
# The abbreviated name of the counterparty
|
|
151
|
+
company_short_name: str = company_short_name("CompanyShortName")
|
|
152
|
+
|
|
153
|
+
# A code identifying the TSO or MO
|
|
154
|
+
operator: str = operator_code("OperatorCode")
|
|
155
|
+
|
|
156
|
+
# Primary-Secondary 1 command-and-control and monitoring method. Refers to the methodology or system utilized for
|
|
157
|
+
# regulating and overseeing power generation units' operations in response to external commands or signals. This
|
|
158
|
+
# method encompasses the process by which instructions are transmitted to power generation units, and their
|
|
159
|
+
# performance is monitored to ensure compliance with these instructions. If has_secondary_1 is set to True, then
|
|
160
|
+
# it must be set to DEDICATED_LINE. At least one of the following combinations must be set:
|
|
161
|
+
# primary_secondary_1_control_method
|
|
162
|
+
# secondary_2_tertiary_control_method
|
|
163
|
+
primary_secondary_1_control_method: Optional[CommandMonitorMethod] = attr(
|
|
164
|
+
default=None, name="CommandOperationMethodPriSec1"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Secondary 2-Tertiary command-and-control and monitoring method. Refers to the methodology or system utilized for
|
|
168
|
+
# regulating and overseeing power generation units' operations in response to external commands or signals. This
|
|
169
|
+
# method encompasses the process by which instructions are transmitted to power generation units, and their
|
|
170
|
+
# performance is monitored to ensure compliance with these instructions.
|
|
171
|
+
secondary_2_tertiary_control_method: Optional[CommandMonitorMethod] = attr(
|
|
172
|
+
default=None, name="CommandOperationMethodSec2Ter1Ter2"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Bid unit price, in JPY/kW/segment
|
|
176
|
+
offer_price: Decimal = price("OfferPrice", 10000.00)
|
|
177
|
+
|
|
178
|
+
# The contract price, in JPY/kW/segment
|
|
179
|
+
contract_price: Decimal = price("ContractPrice", 10000.00)
|
|
180
|
+
|
|
181
|
+
# The performance evaluation coefficient, alpha
|
|
182
|
+
performance_evaluation_coefficient: Decimal = attr(name="PerfEvalCoeff", ge=0.00, le=100.0, decimal_places=2)
|
|
183
|
+
|
|
184
|
+
# The corrected unit price, in JPY/kW/segment
|
|
185
|
+
corrected_unit_price: Decimal = price("CorrectedUnitPrice", 1000000.00)
|
|
186
|
+
|
|
187
|
+
# The commodity combination category. This is only set for non-BSP users.
|
|
188
|
+
sub_requirement: Optional[SubRequirement] = attr(default=None, name="SubRequirementType")
|
|
189
|
+
|
|
190
|
+
# The primary offer quantity in kW. If the API user is a BSP, this field is not set for the contract results
|
|
191
|
+
# generated by the TSO's power source exchange.
|
|
192
|
+
primary_offer_qty: Optional[int] = power_positive("PrimaryOfferQuantityInKw", True)
|
|
193
|
+
|
|
194
|
+
# The secondary 1 offer quantity, in kW. If the API user is a BSP, this field is not set for the contract results
|
|
195
|
+
# generated by the TSO's power source exchange.
|
|
196
|
+
secondary_1_offer_qty: Optional[int] = power_positive("Secondary1OfferQuantityInKw", True)
|
|
197
|
+
|
|
198
|
+
# The secondary 2 offer quantity, in kW. If the API user is a BSP, this field is not set for the contract results
|
|
199
|
+
# generated by the TSO's power source exchange.
|
|
200
|
+
secondary_2_offer_qty: Optional[int] = power_positive("Secondary2OfferQuantityInKw", True)
|
|
201
|
+
|
|
202
|
+
# The tertiary 1 offer quantity, in kW. If the API user is a BSP, this field is not set for the contract results
|
|
203
|
+
# generated by the TSO's power source exchange.
|
|
204
|
+
tertiary_1_offer_qty: Optional[int] = power_positive("Tertiary1OfferQuantityInKw", True)
|
|
205
|
+
|
|
206
|
+
# The tertiary 2 offer quantity, in kW. If the API user is a BSP, this field is not set for the contract results
|
|
207
|
+
# generated by the TSO's power source exchange.
|
|
208
|
+
tertiary_2_offer_qty: Optional[int] = power_positive("Tertiary2OfferQuantityInKw", True)
|
|
209
|
+
|
|
210
|
+
# The primary award quantity, in kW
|
|
211
|
+
primary_award_qty: Optional[int] = power_positive("PrimaryAwardQuantityInKw", True)
|
|
212
|
+
|
|
213
|
+
# The secondary 1 award quantity, in kW
|
|
214
|
+
secondary_1_award_qty: Optional[int] = power_positive("Secondary1AwardQuantityInKw", True)
|
|
215
|
+
|
|
216
|
+
# The secondary 2 award quantity, in kW
|
|
217
|
+
secondary_2_award_qty: Optional[int] = power_positive("Secondary2AwardQuantityInKw", True)
|
|
218
|
+
|
|
219
|
+
# The tertiary 1 award quantity, in kW
|
|
220
|
+
tertiary_1_award_qty: Optional[int] = power_positive("Tertiary1AwardQuantityInKw", True)
|
|
221
|
+
|
|
222
|
+
# The tertiary 2 award quantity, in kW
|
|
223
|
+
tertiary_2_award_qty: Optional[int] = power_positive("Tertiary2AwardQuantityInKw", True)
|
|
224
|
+
|
|
225
|
+
# The primary contract quantity, in kW
|
|
226
|
+
primary_contract_qty: Optional[int] = power_positive("PrimaryContractQuantityInKw", True)
|
|
227
|
+
|
|
228
|
+
# The secondary 1 contract quantity, in kW
|
|
229
|
+
secondary_1_contract_qty: Optional[int] = power_positive("Secondary1ContractQuantityInKw", True)
|
|
230
|
+
|
|
231
|
+
# The secondary 2 contract quantity, in kW
|
|
232
|
+
secondary_2_contract_qty: Optional[int] = power_positive("Secondary2ContractQuantityInKw", True)
|
|
233
|
+
|
|
234
|
+
# The tertiary 1 contract quantity, in kW
|
|
235
|
+
tertiary_1_contract_qty: Optional[int] = power_positive("Tertiary1ContractQuantityInKw", True)
|
|
236
|
+
|
|
237
|
+
# The tertiary 2 contract quantity, in kW
|
|
238
|
+
tertiary_2_contract_qty: Optional[int] = power_positive("Tertiary2ContractQuantityInKw", True)
|
|
239
|
+
|
|
240
|
+
# The primary effective contracted quantity, in kW
|
|
241
|
+
primary_valid_qty: Optional[int] = power_positive("PrimaryValidQuantityInKw", True)
|
|
242
|
+
|
|
243
|
+
# The secondary 1 effective contracted quantity, in kW
|
|
244
|
+
secondary_1_valid_qty: Optional[int] = power_positive("Secondary1ValidQuantityInKw", True)
|
|
245
|
+
|
|
246
|
+
# The secondary 2 effective contracted quantity, in kW
|
|
247
|
+
secondary_2_valid_qty: Optional[int] = power_positive("Secondary2ValidQuantityInKw", True)
|
|
248
|
+
|
|
249
|
+
# The tertiary 1 effective contracted quantity, in kW
|
|
250
|
+
tertiary_1_valid_qty: Optional[int] = power_positive("Tertiary1ValidQuantityInKw", True)
|
|
251
|
+
|
|
252
|
+
# The compound fulfillment quantity, in kW
|
|
253
|
+
compound_valid_qty: Optional[int] = power_positive("CompoundValidQuantityInKw", True)
|
|
254
|
+
|
|
255
|
+
# The primary invalid contract quantity, in kW
|
|
256
|
+
primary_invalid_qty: Optional[int] = power_positive("PrimaryInvalidQuantityInKw", True)
|
|
257
|
+
|
|
258
|
+
# The secondary 1 invalid contract quantity, in kW
|
|
259
|
+
secondary_1_invalid_qty: Optional[int] = power_positive("Secondary1InvalidQuantityInKw", True)
|
|
260
|
+
|
|
261
|
+
# The secondary 2 invalid contract quantity, in kW
|
|
262
|
+
secondary_2_invalid_qty: Optional[int] = power_positive("Secondary2InvalidQuantityInKw", True)
|
|
263
|
+
|
|
264
|
+
# The tertiary 1 invalid contract quantity, in kW
|
|
265
|
+
tertiary_1_invalid_qty: Optional[int] = power_positive("Tertiary1InvalidQuantityInKw", True)
|
|
266
|
+
|
|
267
|
+
# Name of the file containing the negative baseload data
|
|
268
|
+
negative_baseload_file: Optional[str] = baseload_file_name("BaselineLoadFileNameNeg", True)
|
|
269
|
+
|
|
270
|
+
# Name of the file containing the positive baseload data
|
|
271
|
+
positive_baseload_file: Optional[str] = baseload_file_name("BaselineLoadFileNamePos", True)
|
|
272
|
+
|
|
273
|
+
# The date and time when the offer was submitted. If the API user is a BSP, this attribute is not set for the
|
|
274
|
+
# contract results generated by the TSO's power source exchange.
|
|
275
|
+
submission_time: Optional[DateTime] = attr(default=None, name="SubmissionTime")
|
|
276
|
+
|
|
277
|
+
# Contract result (full, partial)
|
|
278
|
+
offer_award_level: ContractResult = attr(name="OfferAwardedLevel")
|
|
279
|
+
|
|
280
|
+
# The ID of the offer to which this stack belongs
|
|
281
|
+
offer_id: Optional[str] = offer_id("OfferId", True)
|
|
282
|
+
|
|
283
|
+
# The source of the contract
|
|
284
|
+
contract_source: ContractSource = attr(name="ContractSource")
|
|
285
|
+
|
|
286
|
+
# Whether we are before gate close or after gate close
|
|
287
|
+
gate_closed: BooleanFlag = attr(name="AfterGC")
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class AwardResult(Payload, tag="AwardResults"):
|
|
291
|
+
"""Contains a number of bid rewards associated with a block of time and trade direction."""
|
|
292
|
+
|
|
293
|
+
# The start date and time of the block associated with the awards
|
|
294
|
+
start: DateTime = attr(name="StartTime")
|
|
295
|
+
|
|
296
|
+
# The end date and time of the block associated with the awards
|
|
297
|
+
end: DateTime = attr(name="EndTime")
|
|
298
|
+
|
|
299
|
+
# The direction of the associated trades
|
|
300
|
+
direction: Direction = attr(name="Direction")
|
|
301
|
+
|
|
302
|
+
# The bid awards associated with these parameters
|
|
303
|
+
data: List[Award] = element(tag="AwardResultsData", min_length=1)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class AwardResponse(AwardQuery, tag="AwardResultsQuery"):
|
|
307
|
+
"""Contains the results of a bid award query."""
|
|
308
|
+
|
|
309
|
+
# The bid awards associated with the query
|
|
310
|
+
results: Optional[List[AwardResult]] = wrapped(default=None, path="AwardResultsQueryResponse")
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Contains enums common to all MMS types."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from enum import IntEnum
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AreaCode(Enum):
|
|
8
|
+
"""Represents the area code of the market."""
|
|
9
|
+
|
|
10
|
+
HOKKAIDO = "01"
|
|
11
|
+
TOHOKU = "02"
|
|
12
|
+
TOKYO = "03"
|
|
13
|
+
CHUBU = "04"
|
|
14
|
+
HOKURIKU = "05"
|
|
15
|
+
KANSAI = "06"
|
|
16
|
+
CHUGOKU = "07"
|
|
17
|
+
SHIKOKU = "08"
|
|
18
|
+
KYUSHU = "09"
|
|
19
|
+
OKINAWA = "10"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Direction(Enum):
|
|
23
|
+
"""Represents the reserve direction of the offer."""
|
|
24
|
+
|
|
25
|
+
SELL = "1" # Increasing the reserves (sell)
|
|
26
|
+
# Note: Support for the BUY direction was removed from the MMS API
|
|
27
|
+
# BUY = "2" # Decreasing the reserves (buy)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ContractResult(Enum):
|
|
31
|
+
"""Represents the result of a contract."""
|
|
32
|
+
|
|
33
|
+
FULL = "1"
|
|
34
|
+
PARTIAL = "2"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Frequency(IntEnum):
|
|
38
|
+
"""Represents the frequency of power sources."""
|
|
39
|
+
|
|
40
|
+
EAST = 50
|
|
41
|
+
WEST = 60
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ResourceType(Enum):
|
|
45
|
+
"""How the power generation unit produces electricity."""
|
|
46
|
+
|
|
47
|
+
THERMAL = "01"
|
|
48
|
+
HYDRO = "02"
|
|
49
|
+
PUMP = "03"
|
|
50
|
+
BATTERY = "04"
|
|
51
|
+
VPP_GEN = "05"
|
|
52
|
+
VPP_GEN_AND_DEM = "06"
|
|
53
|
+
VPP_DEM = "07"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class CommandMonitorMethod(Enum):
|
|
57
|
+
"""Describes how the power generation unit is monitored and commanded."""
|
|
58
|
+
|
|
59
|
+
DEDICATED_LINE = "1"
|
|
60
|
+
SIMPLE_COMMAND = "2"
|
|
61
|
+
OFFLINE = "3"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class BooleanFlag(Enum):
|
|
65
|
+
"""Represents a Boolean value as an enumeration.
|
|
66
|
+
|
|
67
|
+
There are many places throughout the MMS documenation where Boolean values are treated as enums for reasons that are
|
|
68
|
+
not clear. This is a common pattern and this class is provided to make it easier to handle these cases without
|
|
69
|
+
having many different enum classes
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
YES = "1"
|
|
73
|
+
NO = "0"
|