pfund-blocks 0.0.1__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.
- pfund_blocks-0.0.1/PKG-INFO +14 -0
- pfund_blocks-0.0.1/README.md +4 -0
- pfund_blocks-0.0.1/pyproject.toml +26 -0
- pfund_blocks-0.0.1/pyproject.toml.orig +24 -0
- pfund_blocks-0.0.1/src/pfund_blocks/__init__.py +0 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/markets/__init__.py +4 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/markets/market_base.py +40 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/__init__.py +13 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/asset_type.py +137 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/mixins/crypto.py +12 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/mixins/derivative.py +25 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/mixins/etf.py +11 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/mixins/forex.py +11 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/mixins/future.py +35 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/mixins/index.py +11 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/mixins/inverse.py +11 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/mixins/option.py +43 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/mixins/perpetual.py +26 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/mixins/stock.py +11 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/product_base.py +222 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/product_basis.py +67 -0
- pfund_blocks-0.0.1/src/pfund_blocks/entities/products/product_factory.py +38 -0
- pfund_blocks-0.0.1/src/pfund_blocks/enums/asset_type.py +86 -0
- pfund_blocks-0.0.1/src/pfund_blocks/enums/env.py +11 -0
- pfund_blocks-0.0.1/src/pfund_blocks/enums/month_code.py +25 -0
- pfund_blocks-0.0.1/src/pfund_blocks/enums/option_type.py +6 -0
- pfund_blocks-0.0.1/src/pfund_blocks/enums/timeframe.py +102 -0
- pfund_blocks-0.0.1/src/pfund_blocks/resolution.py +287 -0
- pfund_blocks-0.0.1/src/pfund_blocks/utils/__init__.py +13 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: pfund-blocks
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Building blocks for `pfund`
|
|
5
|
+
Author: softwareentrepreneer
|
|
6
|
+
Author-email: softwareentrepreneer <softwareentrepreneer+pfund-blocks@gmail.com>
|
|
7
|
+
Requires-Dist: pydantic>=2.14.0
|
|
8
|
+
Requires-Python: >=3.13
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
[pfund]: https://github.com/PFund-Software-Ltd/pfund
|
|
12
|
+
|
|
13
|
+
# pfund-blocks
|
|
14
|
+
Building blocks for [pfund]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pfund-blocks"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Building blocks for `pfund`"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
dependencies = ["pydantic>=2.14.0"]
|
|
8
|
+
|
|
9
|
+
[[project.authors]]
|
|
10
|
+
name = "softwareentrepreneer"
|
|
11
|
+
email = "softwareentrepreneer+pfund-blocks@gmail.com"
|
|
12
|
+
|
|
13
|
+
[build-system]
|
|
14
|
+
requires = ["uv_build>=0.13.5,<0.14.0"]
|
|
15
|
+
build-backend = "uv_build"
|
|
16
|
+
|
|
17
|
+
[tool.uv]
|
|
18
|
+
exclude-newer = "14 days"
|
|
19
|
+
|
|
20
|
+
[tool.uv.exclude-newer-package]
|
|
21
|
+
uv_build = false
|
|
22
|
+
pfund-kit = false
|
|
23
|
+
|
|
24
|
+
[tool.uv.build-backend]
|
|
25
|
+
module-name = "pfund_blocks"
|
|
26
|
+
module-root = "src"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pfund-blocks"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Building blocks for `pfund`"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "softwareentrepreneer", email = "softwareentrepreneer+pfund-blocks@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.13"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"pydantic>=2.14.0",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[build-system]
|
|
15
|
+
requires = ["uv_build>=0.13.5,<0.14.0"]
|
|
16
|
+
build-backend = "uv_build"
|
|
17
|
+
|
|
18
|
+
[tool.uv]
|
|
19
|
+
exclude-newer = "14 days"
|
|
20
|
+
exclude-newer-package = { uv_build = false, pfund-kit = false }
|
|
21
|
+
|
|
22
|
+
[tool.uv.build-backend]
|
|
23
|
+
module-name = "pfund_blocks"
|
|
24
|
+
module-root = "src"
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
from datetime import datetime, timedelta
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field, ConfigDict
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseMarket(BaseModel):
|
|
8
|
+
model_config = ConfigDict(extra="allow")
|
|
9
|
+
|
|
10
|
+
symbol: str
|
|
11
|
+
base_asset: str
|
|
12
|
+
quote_asset: str
|
|
13
|
+
asset_type: str
|
|
14
|
+
tick_size: Decimal | None = Field(
|
|
15
|
+
default=None, description="Tick size, minimum price increment"
|
|
16
|
+
)
|
|
17
|
+
lot_size: Decimal | None = Field(
|
|
18
|
+
default=None, description="Lot size, minimum quantity incrementc"
|
|
19
|
+
)
|
|
20
|
+
min_leverage: Decimal | None = Field(default=None, description="Minimum leverage")
|
|
21
|
+
max_leverage: Decimal | None = Field(default=None, description="Maximum leverage")
|
|
22
|
+
leverage_step: Decimal | None = Field(
|
|
23
|
+
default=None, description="Leverage step size"
|
|
24
|
+
)
|
|
25
|
+
min_price: Decimal | None = Field(default=None, description="Minimum price")
|
|
26
|
+
max_price: Decimal | None = Field(default=None, description="Maximum price")
|
|
27
|
+
min_quantity: Decimal | None = Field(
|
|
28
|
+
default=None, description="Minimum order quantity"
|
|
29
|
+
)
|
|
30
|
+
max_quantity: Decimal | None = Field(
|
|
31
|
+
default=None, description="Maximum order quantity"
|
|
32
|
+
)
|
|
33
|
+
listed_at: datetime | None = Field(
|
|
34
|
+
default=None, description="Date the market was listed"
|
|
35
|
+
)
|
|
36
|
+
expiration: datetime | None = Field(default=None, description="expiration date")
|
|
37
|
+
settle_currency: str | None = Field(default=None, description="Settlement currency")
|
|
38
|
+
funding_interval: timedelta | None = Field(
|
|
39
|
+
default=None, description="Funding interval"
|
|
40
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from pfund_blocks.entities.products.product_factory import ProductFactory
|
|
2
|
+
from pfund_blocks.entities.products.product_base import BaseProduct, ProductKey
|
|
3
|
+
from pfund_blocks.entities.products.asset_type import AssetType
|
|
4
|
+
from pfund_blocks.entities.products.product_basis import ProductBasis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"ProductFactory",
|
|
9
|
+
"BaseProduct",
|
|
10
|
+
"ProductKey",
|
|
11
|
+
"AssetType",
|
|
12
|
+
"ProductBasis",
|
|
13
|
+
]
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from functools import cached_property
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, ConfigDict, field_validator, model_validator
|
|
6
|
+
|
|
7
|
+
from pfund_blocks.enums.asset_type import (
|
|
8
|
+
ASSET_TYPE_ALIASES,
|
|
9
|
+
AllAssetType,
|
|
10
|
+
AssetTypeModifier,
|
|
11
|
+
CryptoAssetType,
|
|
12
|
+
TraditionalAssetType,
|
|
13
|
+
PredictionMarketAssetType,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AssetType(BaseModel):
|
|
18
|
+
model_config = ConfigDict(
|
|
19
|
+
arbitrary_types_allowed=True, frozen=True, ignored_types=(cached_property,)
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
value: str # e.g. 'STOCK'/'STK', 'INVERSE-FUTURE'/'IFUT', 'CRYPTO' etc.
|
|
23
|
+
|
|
24
|
+
@model_validator(mode="before")
|
|
25
|
+
@classmethod
|
|
26
|
+
def _coerce_string(cls, data: Any) -> Any:
|
|
27
|
+
# allow a bare string (e.g. "PERP") to be used wherever an
|
|
28
|
+
# AssetType is expected, by treating it as the `value` field
|
|
29
|
+
if isinstance(data, str):
|
|
30
|
+
return {"value": data.upper()}
|
|
31
|
+
return data
|
|
32
|
+
|
|
33
|
+
@staticmethod
|
|
34
|
+
def _standardize_asset_type_string(asset_type_string: str) -> str:
|
|
35
|
+
"""
|
|
36
|
+
Expand aliases (e.g. 'IPERP' -> 'INVERSE-PERPETUAL') into their canonical hyphenated form.
|
|
37
|
+
"""
|
|
38
|
+
asset_types_and_modifiers = asset_type_string.split("-")
|
|
39
|
+
standardized_asset_types_and_modifiers = [
|
|
40
|
+
ASSET_TYPE_ALIASES.get(atm.upper(), atm)
|
|
41
|
+
for atm in asset_types_and_modifiers
|
|
42
|
+
]
|
|
43
|
+
return "-".join(standardized_asset_types_and_modifiers)
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def _parse_asset_type_string_to_tuple(
|
|
47
|
+
asset_type_string: str,
|
|
48
|
+
) -> tuple[AssetTypeModifier | AllAssetType, ...]:
|
|
49
|
+
"""
|
|
50
|
+
Convert asset type string (e.g. 'INVERSE-FUTURE') to tuple of AssetTypeModifier and AssetType (e.g. (AssetTypeModifier.INVERSE, AssetType.FUTURE)).
|
|
51
|
+
"""
|
|
52
|
+
asset_type_string = AssetType._standardize_asset_type_string(asset_type_string)
|
|
53
|
+
parsed: list[AssetTypeModifier | AllAssetType] = []
|
|
54
|
+
for atm in asset_type_string.split("-"):
|
|
55
|
+
if atm in AssetTypeModifier.__members__:
|
|
56
|
+
parsed.append(AssetTypeModifier[atm])
|
|
57
|
+
elif atm in AllAssetType.__members__:
|
|
58
|
+
parsed.append(AllAssetType[atm])
|
|
59
|
+
# NOTE: some aliases are not in AllAssetType, e.g. 'SPOT' only exists in CryptoAssetType.
|
|
60
|
+
# The sub-enums' values are AllAssetType members, so normalize to AllAssetType.
|
|
61
|
+
elif atm in TraditionalAssetType.__members__:
|
|
62
|
+
parsed.append(AllAssetType(TraditionalAssetType[atm]))
|
|
63
|
+
elif atm in CryptoAssetType.__members__:
|
|
64
|
+
parsed.append(AllAssetType(CryptoAssetType[atm]))
|
|
65
|
+
elif atm in PredictionMarketAssetType.__members__:
|
|
66
|
+
parsed.append(AllAssetType(PredictionMarketAssetType[atm]))
|
|
67
|
+
else:
|
|
68
|
+
raise ValueError(f"Invalid asset type: {atm}")
|
|
69
|
+
return tuple(parsed)
|
|
70
|
+
|
|
71
|
+
@field_validator("value", mode="after")
|
|
72
|
+
@classmethod
|
|
73
|
+
def _normalize(cls, v: str) -> str:
|
|
74
|
+
return "-".join(cls._parse_asset_type_string_to_tuple(v))
|
|
75
|
+
|
|
76
|
+
@cached_property
|
|
77
|
+
def as_tuple(self) -> tuple[AssetTypeModifier | AllAssetType, ...]:
|
|
78
|
+
return self._parse_asset_type_string_to_tuple(self.value)
|
|
79
|
+
|
|
80
|
+
def __eq__(self, other: Any):
|
|
81
|
+
if isinstance(other, str):
|
|
82
|
+
other_tuple = self._parse_asset_type_string_to_tuple(other)
|
|
83
|
+
return self.as_tuple == other_tuple
|
|
84
|
+
elif isinstance(other, AssetType):
|
|
85
|
+
return self.as_tuple == other.as_tuple
|
|
86
|
+
return False
|
|
87
|
+
|
|
88
|
+
def __hash__(self) -> int:
|
|
89
|
+
return hash(self.as_tuple)
|
|
90
|
+
|
|
91
|
+
def __contains__(self, item: Any):
|
|
92
|
+
return item in self.as_tuple
|
|
93
|
+
|
|
94
|
+
def __iter__(self):
|
|
95
|
+
return iter(self.as_tuple)
|
|
96
|
+
|
|
97
|
+
def __len__(self):
|
|
98
|
+
return len(self.as_tuple)
|
|
99
|
+
|
|
100
|
+
def __str__(self):
|
|
101
|
+
return self.value
|
|
102
|
+
|
|
103
|
+
def is_inverse(self) -> bool:
|
|
104
|
+
return AssetTypeModifier.INVERSE in self.as_tuple
|
|
105
|
+
|
|
106
|
+
def is_crypto(self) -> bool:
|
|
107
|
+
return AllAssetType.CRYPTO in self.as_tuple
|
|
108
|
+
|
|
109
|
+
def is_future(self) -> bool:
|
|
110
|
+
return AllAssetType.FUTURE in self.as_tuple
|
|
111
|
+
|
|
112
|
+
def is_perpetual(self) -> bool:
|
|
113
|
+
return AllAssetType.PERPETUAL in self.as_tuple
|
|
114
|
+
|
|
115
|
+
def is_option(self) -> bool:
|
|
116
|
+
return AllAssetType.OPTION in self.as_tuple
|
|
117
|
+
|
|
118
|
+
def is_stock(self) -> bool:
|
|
119
|
+
return AllAssetType.STOCK in self.as_tuple
|
|
120
|
+
|
|
121
|
+
def is_etf(self) -> bool:
|
|
122
|
+
return AllAssetType.ETF in self.as_tuple
|
|
123
|
+
|
|
124
|
+
def is_forex(self) -> bool:
|
|
125
|
+
return AllAssetType.FOREX in self.as_tuple
|
|
126
|
+
|
|
127
|
+
def is_bond(self) -> bool:
|
|
128
|
+
return AllAssetType.BOND in self.as_tuple
|
|
129
|
+
|
|
130
|
+
def is_mutual_fund(self) -> bool:
|
|
131
|
+
return AllAssetType.FUND in self.as_tuple
|
|
132
|
+
|
|
133
|
+
def is_commodity(self) -> bool:
|
|
134
|
+
return AllAssetType.CMDTY in self.as_tuple
|
|
135
|
+
|
|
136
|
+
def is_index(self) -> bool:
|
|
137
|
+
return AllAssetType.INDEX in self.as_tuple
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# pyright: reportAttributeAccessIssue=false
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from pfund_blocks.entities.products.product_base import BaseProduct
|
|
8
|
+
|
|
9
|
+
from decimal import Decimal
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DerivativeMixin:
|
|
13
|
+
underlying: str = ""
|
|
14
|
+
# TODO: information that requires data fetching or config loading
|
|
15
|
+
multiplier: Decimal | None = None
|
|
16
|
+
|
|
17
|
+
# contract_unit: str | None = None # e.g. barrels
|
|
18
|
+
# notional: Decimal | None = None
|
|
19
|
+
# leverage: Decimal | None = None
|
|
20
|
+
# initial_margin: Decimal | None = None
|
|
21
|
+
# maintenance_margin: Decimal | None = None
|
|
22
|
+
# settlement_type: SettlementType
|
|
23
|
+
|
|
24
|
+
def __mixin_post_init__(self: DerivativeMixin | BaseProduct):
|
|
25
|
+
self.underlying = self.base_asset # TODO: inaccurate
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from pfund_blocks.entities.products.product_base import BaseProduct
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ETFMixin:
|
|
10
|
+
def _create_symbol(self: BaseProduct) -> str:
|
|
11
|
+
return self.base_asset
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from pfund_blocks.entities.products.product_base import BaseProduct
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ForexMixin:
|
|
10
|
+
def _create_symbol(self: BaseProduct) -> str:
|
|
11
|
+
return self.base_asset + self.quote_asset
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# pyright: reportAttributeAccessIssue=false, reportUninitializedInstanceVariable=false
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from pfund_blocks.entities.products.product_base import BaseProduct
|
|
8
|
+
|
|
9
|
+
from datetime import date
|
|
10
|
+
|
|
11
|
+
from pfund_blocks.entities.products.mixins.derivative import DerivativeMixin
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FutureMixin(DerivativeMixin):
|
|
15
|
+
expiration: date
|
|
16
|
+
contract_code: str = ""
|
|
17
|
+
|
|
18
|
+
def __mixin_post_init__(self):
|
|
19
|
+
super().__mixin_post_init__()
|
|
20
|
+
self.contract_code = self._derive_contract_code()
|
|
21
|
+
|
|
22
|
+
def _derive_contract_code(self):
|
|
23
|
+
from pfund_blocks.enums.month_code import FutureMonthCode
|
|
24
|
+
|
|
25
|
+
expiration_year, expiration_month, _ = str(self.expiration).split("-")
|
|
26
|
+
expiration_year = expiration_year[-2:]
|
|
27
|
+
month_code = [code.value for code in FutureMonthCode][int(expiration_month) - 1]
|
|
28
|
+
contract_code = month_code + expiration_year
|
|
29
|
+
return contract_code
|
|
30
|
+
|
|
31
|
+
def _create_symbol(self: FutureMixin | BaseProduct) -> str:
|
|
32
|
+
"""
|
|
33
|
+
Creates default symbol e.g. ESZ23
|
|
34
|
+
"""
|
|
35
|
+
return self.base_asset + self.contract_code
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from pfund_blocks.entities.products.product_base import BaseProduct
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class IndexMixin:
|
|
10
|
+
def _create_symbol(self: BaseProduct) -> str:
|
|
11
|
+
return self.base_asset
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# pyright: reportAttributeAccessIssue=false, reportUninitializedInstanceVariable=false
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from pfund_blocks.entities.products.product_base import BaseProduct
|
|
8
|
+
|
|
9
|
+
from datetime import date
|
|
10
|
+
from decimal import Decimal
|
|
11
|
+
|
|
12
|
+
from pydantic import Field, field_validator
|
|
13
|
+
|
|
14
|
+
from pfund_blocks.entities.products.mixins.derivative import DerivativeMixin
|
|
15
|
+
from pfund_blocks.enums.option_type import OptionType
|
|
16
|
+
from pfund_blocks.utils import trim_trailing_zeros
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# TODO: add Greeks
|
|
20
|
+
class OptionMixin(DerivativeMixin):
|
|
21
|
+
expiration: date
|
|
22
|
+
strike_price: Decimal = Field(ge=0.0)
|
|
23
|
+
option_type: OptionType
|
|
24
|
+
|
|
25
|
+
@field_validator("option_type", mode="before")
|
|
26
|
+
@classmethod
|
|
27
|
+
def _uppercase_option_type(cls, option_type: str) -> str:
|
|
28
|
+
return option_type.upper()
|
|
29
|
+
|
|
30
|
+
@field_validator("strike_price", mode="after")
|
|
31
|
+
@classmethod
|
|
32
|
+
def _remove_redundant_zeros(cls, strike_price: Decimal) -> Decimal:
|
|
33
|
+
return trim_trailing_zeros(strike_price)
|
|
34
|
+
|
|
35
|
+
def _create_symbol(self: OptionMixin | BaseProduct) -> str:
|
|
36
|
+
"""
|
|
37
|
+
Creates default symbol e.g. TSLA241213C00075000 following OSI format (Option Symbology Initiative)
|
|
38
|
+
"""
|
|
39
|
+
expiration = self.expiration.strftime("%y%m%d") # convert expiration to yymmdd
|
|
40
|
+
num_of_digits = 8
|
|
41
|
+
strike_price = str(int(self.strike_price * 1000)).zfill(num_of_digits)
|
|
42
|
+
symbol = self.base_asset + expiration + self.option_type.value[0] + strike_price
|
|
43
|
+
return symbol
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from typing_extensions import override
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from pfund_blocks.entities.products.product_base import BaseProduct
|
|
9
|
+
|
|
10
|
+
from pfund_blocks.entities.products.mixins.future import FutureMixin
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PerpetualMixin(FutureMixin):
|
|
14
|
+
expiration: None = None
|
|
15
|
+
contract_code: None = None
|
|
16
|
+
|
|
17
|
+
@override # override FutureMixin._derive_contract_code
|
|
18
|
+
def _derive_contract_code(self) -> None:
|
|
19
|
+
return None
|
|
20
|
+
|
|
21
|
+
@override # override FutureMixin._create_symbol
|
|
22
|
+
def _create_symbol(self: FutureMixin | BaseProduct) -> str:
|
|
23
|
+
"""
|
|
24
|
+
Creates default symbol e.g. ESZ23
|
|
25
|
+
"""
|
|
26
|
+
return self.base_asset + "_" + self.quote_asset
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from pfund_blocks.entities.products.product_base import BaseProduct
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class StockMixin:
|
|
10
|
+
def _create_symbol(self: StockMixin | BaseProduct) -> str:
|
|
11
|
+
return self.base_asset
|