mainsequence 2.0.3__tar.gz → 2.0.4a0__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.
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/PKG-INFO +1 -1
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/cli/api.py +5 -3
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/cli/cli.py +1 -4
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/__init__.py +1 -1
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/base.py +1 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/models_tdag.py +130 -2
- mainsequence-2.0.4a0/mainsequence/instruments/__init__.py +2 -0
- mainsequence-2.0.4a0/mainsequence/instruments/data_interface/__init__.py +22 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/data_interface/data_interface.py +9 -1
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/interest_rate_swap.py +2 -0
- mainsequence-2.0.4a0/mainsequence/instruments/instruments.default.toml +17 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/indices.py +26 -18
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/settings.py +25 -26
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence.egg-info/PKG-INFO +1 -1
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence.egg-info/SOURCES.txt +1 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/pyproject.toml +1 -1
- mainsequence-2.0.3/mainsequence/instruments/__init__.py +0 -1
- mainsequence-2.0.3/mainsequence/instruments/data_interface/__init__.py +0 -10
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/LICENSE +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/README.md +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/__main__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/cli/config.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/data_sources_interfaces/timescale.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/models_report_studio.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/models_vam.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/utils.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/assets/config.toml +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/assets/favicon.png +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/assets/logo.png +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/core/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/core/theme.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/pages/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/scaffold.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/base_instrument.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/bond.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/european_option.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/json_codec.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/knockout_fx_option.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/position.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/ql_fields.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/vanilla_fx_option.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/black_scholes.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/bond_pricer.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/fx_option_pricer.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/knockout_fx_pricer.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/swap_pricer.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/utils.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/logconf.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/reportbuilder/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/reportbuilder/__main__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/reportbuilder/examples/ms_template_report.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/reportbuilder/model.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/reportbuilder/slide_templates.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/__main__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/config.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/data_nodes/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/data_nodes/build_operations.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/data_nodes/data_nodes.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/data_nodes/persist_managers.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/data_nodes/run_operations.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/data_nodes/utils.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/future_registry.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/utils.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/__main__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/agent_interface.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/config_handling.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/etf_replicator_app.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/generate_report.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/load_external_portfolio.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/news_app.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/portfolio_report_app.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/portfolio_table.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/run_named_portfolio.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/run_portfolio.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/templates/base.html +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/templates/report.html +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/data_nodes/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/data_nodes/external_weights.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/data_nodes/intraday_trend.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/data_nodes/market_cap.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/data_nodes/mock_signal.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/data_nodes/portfolio_replicator.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/prices/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/prices/data_nodes.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/prices/utils.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/rebalance_strategies/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/rebalance_strategies/rebalance_strategies.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/data_nodes.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/enums.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/models.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/notebook_handling.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/portfolio_interface.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/resource_factory/__init__.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/resource_factory/app_factory.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/resource_factory/base_factory.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/resource_factory/rebalance_factory.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/resource_factory/signal_factory.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/utils.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/setup.cfg +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/tests/test_agent.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/tests/test_portfolio.py +0 -0
- {mainsequence-2.0.3 → mainsequence-2.0.4a0}/tests/test_replicator.py +0 -0
@@ -38,6 +38,9 @@ def _refresh_token() -> str | None:
|
|
38
38
|
return tok.get("refresh")
|
39
39
|
|
40
40
|
def login(email: str, password: str) -> dict:
|
41
|
+
email = (email or "").strip()
|
42
|
+
password = (password or "").rstrip("\r\n")
|
43
|
+
|
41
44
|
url = _full(AUTH_PATHS["obtain"])
|
42
45
|
payload = {"email": email, "password": password} # server expects 'email'
|
43
46
|
r = S.post(url, data=json.dumps(payload))
|
@@ -178,9 +181,8 @@ def get_project_token(project_id: int | str) -> str:
|
|
178
181
|
token = None
|
179
182
|
if r.headers.get("content-type","").startswith("application/json"):
|
180
183
|
data = r.json()
|
181
|
-
token=data["development"]
|
182
|
-
if not token:
|
184
|
+
token=data["development"][0]
|
183
185
|
token = (r.text or "").strip()
|
184
186
|
if not token:
|
185
187
|
raise ApiError("Project token response did not include a token.")
|
186
|
-
return token
|
188
|
+
return token
|
@@ -129,7 +129,6 @@ def _render_projects_table(items: list[dict], links: dict, base_dir: str, org_sl
|
|
129
129
|
def login(
|
130
130
|
email: str = typer.Argument(..., help="Email/username (server expects 'email' field)"),
|
131
131
|
password: Optional[str] = typer.Option(None, prompt=True, hide_input=True, help="Password"),
|
132
|
-
export: bool = typer.Option(False, "--export", help='Print `export MAIN_SEQUENCE_USER_TOKEN=...` so you can eval it'),
|
133
132
|
no_status: bool = typer.Option(False, "--no-status", help="Do not print projects table after login")
|
134
133
|
):
|
135
134
|
"""
|
@@ -147,9 +146,7 @@ def login(
|
|
147
146
|
typer.secho(f"Signed in as {res['username']} (Backend: {res['backend']})", fg=typer.colors.GREEN)
|
148
147
|
typer.echo(f"Projects base folder: {base}")
|
149
148
|
|
150
|
-
|
151
|
-
if export and tok:
|
152
|
-
print(f'export MAIN_SEQUENCE_USER_TOKEN="{tok}"')
|
149
|
+
|
153
150
|
|
154
151
|
if not no_status:
|
155
152
|
try:
|
@@ -4,7 +4,7 @@ from .models_tdag import (request_to_datetime, LocalTimeSeriesDoesNotExist, Dyna
|
|
4
4
|
SourceTableConfigurationDoesNotExist, LocalTimeSerieUpdateDetails,
|
5
5
|
JSON_COMPRESSED_PREFIX, Scheduler, SchedulerDoesNotExist, LocalTimeSerie,
|
6
6
|
DynamicTableMetaData, DynamicTableDataSource,DUCK_DB,
|
7
|
-
ColumnMetaData,Artifact,TableMetaData ,DataFrequency,SourceTableConfiguration,
|
7
|
+
ColumnMetaData,Artifact,TableMetaData ,DataFrequency,SourceTableConfiguration,Constant,
|
8
8
|
Project, UniqueIdentifierRangeMap, LocalTimeSeriesHistoricalUpdate,
|
9
9
|
UpdateStatistics, DataSource, PodDataSource, SessionDataSource)
|
10
10
|
|
@@ -18,9 +18,10 @@ from typing import Union
|
|
18
18
|
import time
|
19
19
|
import os
|
20
20
|
from mainsequence.logconf import logger
|
21
|
+
from threading import RLock
|
21
22
|
|
22
|
-
from pydantic import BaseModel, Field, field_validator
|
23
|
-
from typing import Optional, List, Dict, Any, TypedDict, Tuple
|
23
|
+
from pydantic import BaseModel, Field, field_validator,computed_field
|
24
|
+
from typing import Optional, List, Dict, Any, TypedDict, Tuple, ClassVar
|
24
25
|
from .data_sources_interfaces import timescale as TimeScaleInterface
|
25
26
|
from functools import wraps
|
26
27
|
import math
|
@@ -29,6 +30,9 @@ import base64
|
|
29
30
|
import numpy as np
|
30
31
|
import concurrent.futures
|
31
32
|
|
33
|
+
from cachetools import TTLCache, cachedmethod
|
34
|
+
from operator import attrgetter
|
35
|
+
|
32
36
|
_default_data_source = None # Module-level cache
|
33
37
|
|
34
38
|
JSON_COMPRESSED_PREFIX = ["json_compressed", "jcomp_"]
|
@@ -2272,5 +2276,129 @@ class PodDataSource:
|
|
2272
2276
|
return f"{self.data_source.related_resource}"
|
2273
2277
|
|
2274
2278
|
|
2279
|
+
|
2280
|
+
def _norm_value(v: Any) -> Any:
|
2281
|
+
"""Normalize values into hashable, deterministic forms for the cache key."""
|
2282
|
+
# Project objects → their integer IDs (project scoped vs global)
|
2283
|
+
if Project and isinstance(v, Project):
|
2284
|
+
return getattr(v, "id", v)
|
2285
|
+
|
2286
|
+
# Common iterables → sorted tuples to ignore order in queries like name__in
|
2287
|
+
if isinstance(v, (set, list, tuple)):
|
2288
|
+
# Convert nested items too, just in case
|
2289
|
+
return tuple(sorted(_norm_value(x) for x in v))
|
2290
|
+
|
2291
|
+
# Dicts → sorted (k,v) tuples
|
2292
|
+
if isinstance(v, dict):
|
2293
|
+
return tuple(sorted((k, _norm_value(val)) for k, val in v.items()))
|
2294
|
+
|
2295
|
+
return v # primitives pass through
|
2296
|
+
def _norm_kwargs(kwargs: Dict[str, Any]) -> Tuple[Tuple[str, Any], ...]:
|
2297
|
+
"""Stable, hashable key from kwargs (order-insensitive)."""
|
2298
|
+
items = []
|
2299
|
+
for k, v in kwargs.items():
|
2300
|
+
# Special-case a big `name__in` so you don’t produce huge keys.
|
2301
|
+
if k == "name__in" and isinstance(v, (list, tuple, set)):
|
2302
|
+
items.append((k, tuple(sorted(str(x) for x in v))))
|
2303
|
+
else:
|
2304
|
+
items.append((k, _norm_value(v)))
|
2305
|
+
return tuple(sorted(items))
|
2306
|
+
|
2307
|
+
class Constant(BasePydanticModel, BaseObjectOrm):
|
2308
|
+
"""
|
2309
|
+
Simple scoped constant.
|
2310
|
+
- Global when project is None.
|
2311
|
+
- Project-scoped when project is set.
|
2312
|
+
|
2313
|
+
Uniqueness (enforced in DB/service layer):
|
2314
|
+
* Global: (organization_owner, name)
|
2315
|
+
* Per-project: (organization_owner, project, name)
|
2316
|
+
"""
|
2317
|
+
id: Optional[int]
|
2318
|
+
|
2319
|
+
name: str = Field(
|
2320
|
+
...,
|
2321
|
+
max_length=255,
|
2322
|
+
description="UPPER_SNAKE_CASE; optional category via double-underscore, e.g. 'CURVE__US_TREASURIES'."
|
2323
|
+
)
|
2324
|
+
value: Any = Field(
|
2325
|
+
...,
|
2326
|
+
description="Small JSON value (string/number/bool/object/array). Keep it small (e.g., <=10KB).",
|
2327
|
+
)
|
2328
|
+
project: Optional[Union[Project,int]] = Field(
|
2329
|
+
None,
|
2330
|
+
description="Project ID; None ⇒ global."
|
2331
|
+
)
|
2332
|
+
category: Optional[str] = None
|
2333
|
+
|
2334
|
+
# Class-level cache & lock (Pydantic ignores ClassVar)
|
2335
|
+
_filter_cache: ClassVar[TTLCache] = TTLCache(maxsize=512, ttl=600)
|
2336
|
+
_get_cache: ClassVar[TTLCache] = TTLCache(maxsize=1024, ttl=600)
|
2337
|
+
|
2338
|
+
|
2339
|
+
_cache_lock: ClassVar[RLock] = RLock()
|
2340
|
+
|
2341
|
+
model_config = dict(from_attributes=True) # allows .model_validate(from_orm_obj)
|
2342
|
+
|
2343
|
+
|
2344
|
+
@classmethod
|
2345
|
+
@cachedmethod(
|
2346
|
+
lambda cls: cls._filter_cache, # <- resolves to the real TTLCache
|
2347
|
+
lock=lambda cls: cls._cache_lock,
|
2348
|
+
key=lambda cls, **kw: _norm_kwargs(kw)
|
2349
|
+
)
|
2350
|
+
def filter(cls, **kwargs):
|
2351
|
+
# Delegate to your real filter (API/DB) only on cache miss
|
2352
|
+
return super().filter(**kwargs)
|
2353
|
+
|
2354
|
+
@classmethod
|
2355
|
+
@cachedmethod(
|
2356
|
+
lambda cls: cls._get_cache,
|
2357
|
+
lock=lambda cls: cls._cache_lock,
|
2358
|
+
key=lambda cls, **kw: _norm_kwargs(kw),
|
2359
|
+
)
|
2360
|
+
def get(cls, **kwargs):
|
2361
|
+
# e.g. get(name="CURVE__M_BONOS", project=None)
|
2362
|
+
return super().get(**kwargs)
|
2363
|
+
|
2364
|
+
@classmethod
|
2365
|
+
def get_value(cls,name:str,project_id:Optional[int]=None):
|
2366
|
+
return cls.get(name=name,project_id=project_id).value
|
2367
|
+
|
2368
|
+
@classmethod
|
2369
|
+
def invalidate_filter_cache(cls) -> None:
|
2370
|
+
cls._filter_cache.clear()
|
2371
|
+
|
2372
|
+
@classmethod
|
2373
|
+
def create_constants_if_not_exist(cls,constants_to_create: dict):
|
2374
|
+
# crete global constants if not exist in backed
|
2375
|
+
|
2376
|
+
# constants_to_create=dict(
|
2377
|
+
# TIIE_28_UID = "TIIE_28",
|
2378
|
+
# TIIE_91_UID = "TIIE_91",
|
2379
|
+
# TIIE_182_UID = "TIIE_182",
|
2380
|
+
# TIIE_OVERNIGHT_UID = "TIIE_OVERNIGHT",
|
2381
|
+
#
|
2382
|
+
# CETE_28_UID = "CETE_28",
|
2383
|
+
# CETE_91_UID = "CETE_91",
|
2384
|
+
# CETE_182_UID = "CETE_182",
|
2385
|
+
#
|
2386
|
+
# # Curve identifiers
|
2387
|
+
# TIIE_28_ZERO_CURVE = "F_TIIE_28_VALMER",
|
2388
|
+
# M_BONOS_ZERO_CURVE = "M_BONOS_ZERO_OTR",
|
2389
|
+
#
|
2390
|
+
#
|
2391
|
+
# DISCOUNT_CURVES_TABLE = "discount_curves",
|
2392
|
+
# REFERENCE_RATES_FIXING_TABLE = "fixing_rates_1d",
|
2393
|
+
# )
|
2394
|
+
existing_constants = cls.filter(name__in=list(constants_to_create.keys()))
|
2395
|
+
existing_constants_names = [c.name for c in existing_constants]
|
2396
|
+
constants_to_register = {k: v for k, v in constants_to_create.items() if k not in existing_constants_names}
|
2397
|
+
created_constants=[]
|
2398
|
+
for k, v in constants_to_register.items():
|
2399
|
+
new_constant = cls.create(name=k, value=v)
|
2400
|
+
created_constants.append(new_constant)
|
2401
|
+
return created_constants
|
2402
|
+
|
2275
2403
|
SessionDataSource = PodDataSource()
|
2276
2404
|
SessionDataSource.set_remote_db()
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from .data_interface import DateInfo, MockDataInterface, MSInterface
|
2
|
+
from mainsequence.client import Constant as _C
|
3
|
+
|
4
|
+
import os
|
5
|
+
|
6
|
+
def _make_backend():
|
7
|
+
backend = os.getenv("MSI_DATA_BACKEND", "mock").lower()
|
8
|
+
return MSInterface() if backend == "mainsequence" else MockDataInterface()
|
9
|
+
|
10
|
+
# export a single, uniform instance
|
11
|
+
data_interface = _make_backend()
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
constants_to_create=dict(
|
16
|
+
|
17
|
+
|
18
|
+
DISCOUNT_CURVES_TABLE = "discount_curves",
|
19
|
+
REFERENCE_RATES_FIXING_TABLE = "fixing_rates_1d",
|
20
|
+
)
|
21
|
+
|
22
|
+
_C.create_constants_if_not_exist(constants_to_create)
|
@@ -2,12 +2,21 @@ import datetime
|
|
2
2
|
from typing import Dict, Optional, TypedDict, Any
|
3
3
|
import random
|
4
4
|
from mainsequence.instruments.utils import to_ql_date
|
5
|
+
import mainsequence.client as msc
|
5
6
|
import QuantLib as ql
|
6
7
|
import os
|
7
8
|
import pandas as pd
|
8
9
|
from pathlib import Path
|
9
10
|
|
10
11
|
|
12
|
+
DISCOUNT_CURVES_TABLE=msc.Constant.get_or_none(name="DISCOUNT_CURVES_TABLE")
|
13
|
+
REFERENCE_RATES_FIXING_TABLE = msc.Constant.get_or_none(name="REFERENCE_RATES_FIXING_TABLE")
|
14
|
+
|
15
|
+
assert DISCOUNT_CURVES_TABLE is not None, "DISCOUNT_CURVES_TABLE not found in constants"
|
16
|
+
assert REFERENCE_RATES_FIXING_TABLE is not None, "REFERENCE_RATES_FIXING_TABLE not found in constants"
|
17
|
+
|
18
|
+
|
19
|
+
|
11
20
|
class DateInfo(TypedDict, total=False):
|
12
21
|
"""Defines the date range for a data query."""
|
13
22
|
start_date: Optional[datetime.datetime]
|
@@ -278,7 +287,6 @@ class MSInterface():
|
|
278
287
|
@cachedmethod(cache=attrgetter("_curve_cache"), lock=attrgetter("_curve_cache_lock"))
|
279
288
|
def get_historical_discount_curve(self, curve_name, target_date):
|
280
289
|
from mainsequence.tdag import APIDataNode
|
281
|
-
from mainsequence.instruments.settings import DISCOUNT_CURVES_TABLE
|
282
290
|
data_node = APIDataNode.build_from_identifier(identifier=DISCOUNT_CURVES_TABLE)
|
283
291
|
|
284
292
|
|
@@ -12,6 +12,8 @@ from mainsequence.instruments.pricing_models.swap_pricer import get_swap_cashfl
|
|
12
12
|
from mainsequence.instruments.pricing_models.indices import get_index
|
13
13
|
from mainsequence.instruments.utils import to_ql_date, to_py_date
|
14
14
|
from .base_instrument import InstrumentModel
|
15
|
+
from mainsequence.instruments.pricing_models.indices import build_zero_curve
|
16
|
+
|
15
17
|
|
16
18
|
from .ql_fields import (
|
17
19
|
QuantLibPeriod as QPeriod,
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# instruments.toml — defaults for MainSequence Instruments
|
2
|
+
|
3
|
+
DISCOUNT_CURVES_TABLE = "discount_curves"
|
4
|
+
REFERENCE_RATES_FIXING_TABLE = "fixing_rates_1d"
|
5
|
+
|
6
|
+
TIIE_28_ZERO_CURVE = "F_TIIE_28_VALMER"
|
7
|
+
M_BONOS_ZERO_CURVE = "M_BONOS_ZERO_OTR"
|
8
|
+
|
9
|
+
TIIE_28_UID = "TIIE_28"
|
10
|
+
TIIE_91_UID = "TIIE_91"
|
11
|
+
TIIE_182_UID = "TIIE_182"
|
12
|
+
TIIE_OVERNIGHT_UID = "TIIE_OVERNIGHT"
|
13
|
+
|
14
|
+
CETE_28_UID = "CETE_28"
|
15
|
+
CETE_91_UID = "CETE_91"
|
16
|
+
CETE_182_UID = "CETE_182"
|
17
|
+
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/indices.py
RENAMED
@@ -1,18 +1,17 @@
|
|
1
1
|
# pricing_models/indices.py
|
2
2
|
# -*- coding: utf-8 -*-
|
3
3
|
"""
|
4
|
-
Index factory for QuantLib (identifier-driven
|
4
|
+
Index factory for QuantLib (identifier-driven).
|
5
5
|
|
6
6
|
Usage
|
7
7
|
-----
|
8
8
|
>>> from datetime import date
|
9
|
-
>>> from mainsequence.instruments.settings import TIIE_28_UID
|
10
9
|
>>> from mainsequence.instruments.pricing_models.indices import get_index
|
11
|
-
>>> idx = get_index(
|
10
|
+
>>> idx = get_index("TIIE_28", target_date=date(2024, 6, 14))
|
12
11
|
|
13
12
|
You can also supply a forwarding curve handle:
|
14
13
|
>>> h = ql.RelinkableYieldTermStructureHandle()
|
15
|
-
>>> idx = get_index(
|
14
|
+
>>> idx = get_index("TIIE_28", target_date=date(2025, 9, 16), forwarding_curve=h)
|
16
15
|
|
17
16
|
Notes
|
18
17
|
-----
|
@@ -30,9 +29,8 @@ import QuantLib as ql
|
|
30
29
|
from functools import lru_cache
|
31
30
|
|
32
31
|
from mainsequence.instruments.data_interface import data_interface
|
33
|
-
from mainsequence.instruments import settings
|
34
32
|
from mainsequence.instruments.utils import to_py_date, to_ql_date
|
35
|
-
|
33
|
+
from mainsequence.client import Constant as _C
|
36
34
|
|
37
35
|
# ----------------------------- Cache (ONLY by identifier + date) ----------------------------- #
|
38
36
|
|
@@ -50,8 +48,8 @@ def clear_index_cache() -> None:
|
|
50
48
|
# No tenor tokens; we store the QuantLib Period directly.
|
51
49
|
|
52
50
|
INDEX_CONFIGS: Dict[str, Dict] = {
|
53
|
-
|
54
|
-
curve_uid=
|
51
|
+
_C.get_value(name="TIIE_28_UID"): dict(
|
52
|
+
curve_uid=_C.get_value(name="TIIE_28_ZERO_CURVE"),
|
55
53
|
calendar=(ql.Mexico() if hasattr(ql, "Mexico") else ql.TARGET()),
|
56
54
|
day_counter=ql.Actual360(),
|
57
55
|
currency=(ql.MXNCurrency() if hasattr(ql, "MXNCurrency") else ql.USDCurrency()),
|
@@ -60,8 +58,8 @@ INDEX_CONFIGS: Dict[str, Dict] = {
|
|
60
58
|
bdc=ql.ModifiedFollowing,
|
61
59
|
end_of_month=False,
|
62
60
|
),
|
63
|
-
|
64
|
-
curve_uid=
|
61
|
+
_C.get_value(name="TIIE_91_UID"): dict(
|
62
|
+
curve_uid=_C.get_value(name="TIIE_28_ZERO_CURVE"),
|
65
63
|
calendar=(ql.Mexico() if hasattr(ql, "Mexico") else ql.TARGET()),
|
66
64
|
day_counter=ql.Actual360(),
|
67
65
|
currency=ql.MXNCurrency(),
|
@@ -70,8 +68,8 @@ INDEX_CONFIGS: Dict[str, Dict] = {
|
|
70
68
|
bdc=ql.ModifiedFollowing,
|
71
69
|
end_of_month=False,
|
72
70
|
),
|
73
|
-
|
74
|
-
curve_uid=
|
71
|
+
_C.get_value(name="TIIE_182_UID"): dict(
|
72
|
+
curve_uid=_C.get_value(name="TIIE_28_ZERO_CURVE"),
|
75
73
|
calendar=(ql.Mexico() if hasattr(ql, "Mexico") else ql.TARGET()),
|
76
74
|
day_counter=ql.Actual360(),
|
77
75
|
currency=ql.MXNCurrency(),
|
@@ -81,8 +79,8 @@ INDEX_CONFIGS: Dict[str, Dict] = {
|
|
81
79
|
end_of_month=False,
|
82
80
|
),
|
83
81
|
# Add more identifiers here as needed.
|
84
|
-
|
85
|
-
curve_uid=
|
82
|
+
_C.get_value(name="TIIE_OVERNIGHT_UID"): dict(
|
83
|
+
curve_uid=_C.get_value(name="TIIE_28_ZERO_CURVE"),
|
86
84
|
calendar=(ql.Mexico() if hasattr(ql, "Mexico") else ql.TARGET()),
|
87
85
|
day_counter=ql.Actual360(),
|
88
86
|
currency=ql.MXNCurrency(),
|
@@ -91,8 +89,8 @@ INDEX_CONFIGS: Dict[str, Dict] = {
|
|
91
89
|
bdc=ql.ModifiedFollowing,
|
92
90
|
end_of_month=False,
|
93
91
|
),
|
94
|
-
|
95
|
-
curve_uid=
|
92
|
+
_C.get_value(name="CETE_28_UID"): dict(
|
93
|
+
curve_uid=_C.get_value(name="M_BONOS_ZERO_CURVE"),
|
96
94
|
calendar=(ql.Mexico() if hasattr(ql, "Mexico") else ql.TARGET()),
|
97
95
|
day_counter=ql.Actual360(), # BONOS accrue on Act/360
|
98
96
|
currency=ql.MXNCurrency(),
|
@@ -101,9 +99,19 @@ INDEX_CONFIGS: Dict[str, Dict] = {
|
|
101
99
|
bdc=ql.Following, # “next banking business day” => Following
|
102
100
|
end_of_month=False, # Irrelevant when scheduling by days
|
103
101
|
),
|
102
|
+
_C.get_value(name="CETE_91_UID"): dict(
|
103
|
+
curve_uid=_C.get_value(name="M_BONOS_ZERO_CURVE"),
|
104
|
+
calendar=(ql.Mexico() if hasattr(ql, "Mexico") else ql.TARGET()),
|
105
|
+
day_counter=ql.Actual360(), # BONOS accrue on Act/360
|
106
|
+
currency=ql.MXNCurrency(),
|
107
|
+
period=ql.Period(91, ql.Days), # Coupons every 28 days
|
108
|
+
settlement_days=1, # T+1 in Mexico since May 27–28, 2024
|
109
|
+
bdc=ql.Following, # “next banking business day” => Following
|
110
|
+
end_of_month=False, # Irrelevant when scheduling by days
|
111
|
+
),
|
104
112
|
|
105
|
-
|
106
|
-
curve_uid=
|
113
|
+
_C.get_value(name="CETE_182_UID"): dict(
|
114
|
+
curve_uid=_C.get_value(name="M_BONOS_ZERO_CURVE"),
|
107
115
|
calendar=(ql.Mexico() if hasattr(ql, "Mexico") else ql.TARGET()),
|
108
116
|
day_counter=ql.Actual360(), # BONOS accrue on Act/360
|
109
117
|
currency=ql.MXNCurrency(),
|
@@ -7,6 +7,8 @@ import sys
|
|
7
7
|
from pathlib import Path
|
8
8
|
from types import SimpleNamespace
|
9
9
|
|
10
|
+
|
11
|
+
HERE = Path(__file__).resolve().parent
|
10
12
|
# ---------------- App identity & app dirs ----------------
|
11
13
|
APP_VENDOR = "mainsequence"
|
12
14
|
APP_NAME = "instruments"
|
@@ -15,6 +17,8 @@ APP_ID = f"{APP_VENDOR}/{APP_NAME}"
|
|
15
17
|
# All environment variables use this prefix now.
|
16
18
|
ENV_PREFIX = "MSI" # e.g., MSI_CONFIG_FILE, MSI_DATA_BACKEND
|
17
19
|
ENV_CONFIG_FILE = f"{ENV_PREFIX}_CONFIG_FILE"
|
20
|
+
ENV_DEFAULT_TOML_FILE = f"{ENV_PREFIX}_DEFAULT_TOML_FILE"
|
21
|
+
|
18
22
|
|
19
23
|
def _user_config_root() -> Path:
|
20
24
|
if sys.platform == "win32":
|
@@ -62,31 +66,22 @@ def _load_file_config() -> dict:
|
|
62
66
|
pass
|
63
67
|
return {}
|
64
68
|
|
65
|
-
# ---------------- default TOML (
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
CETE_182_UID = "CETE_182"
|
82
|
-
|
83
|
-
[data]
|
84
|
-
backend = "mock"
|
85
|
-
|
86
|
-
[files]
|
87
|
-
tiie_zero_csv = ""
|
88
|
-
tiie28_fixings_csv = ""
|
89
|
-
"""
|
69
|
+
# ---------------- default TOML (read from a real file next to this module) -----
|
70
|
+
def _read_default_toml_text() -> str | None:
|
71
|
+
"""
|
72
|
+
Returns the text of the default TOML configuration.
|
73
|
+
Order of precedence:
|
74
|
+
1) Path from MSI_DEFAULT_TOML_FILE (if set)
|
75
|
+
2) instruments.default.toml next to this file
|
76
|
+
Returns None if no default file is found/readable.
|
77
|
+
"""
|
78
|
+
candidate = Path(os.getenv(ENV_DEFAULT_TOML_FILE, HERE / "instruments.default.toml")).expanduser()
|
79
|
+
try:
|
80
|
+
if candidate.exists():
|
81
|
+
return candidate.read_text(encoding="utf-8")
|
82
|
+
except Exception:
|
83
|
+
pass
|
84
|
+
return None
|
90
85
|
|
91
86
|
def _existing_config_path() -> Path | None:
|
92
87
|
env_cfg = os.getenv(ENV_CONFIG_FILE)
|
@@ -108,11 +103,15 @@ def _ensure_default_config_file() -> Path | None:
|
|
108
103
|
"""If no config exists anywhere, create one. Never overwrites existing."""
|
109
104
|
if _existing_config_path() is not None:
|
110
105
|
return None
|
106
|
+
default_text = _read_default_toml_text()
|
107
|
+
if default_text is None:
|
108
|
+
return None
|
109
|
+
|
111
110
|
target = Path(os.getenv(ENV_CONFIG_FILE, APP_ROOT / "config.toml")).expanduser()
|
112
111
|
try:
|
113
112
|
target.parent.mkdir(parents=True, exist_ok=True) # ensure parent dir only
|
114
113
|
if not target.exists():
|
115
|
-
target.write_text(
|
114
|
+
target.write_text(default_text, encoding="utf-8")
|
116
115
|
except Exception:
|
117
116
|
return None
|
118
117
|
return target
|
@@ -37,6 +37,7 @@ mainsequence/dashboards/streamlit/pages/__init__.py
|
|
37
37
|
mainsequence/instrumentation/__init__.py
|
38
38
|
mainsequence/instrumentation/utils.py
|
39
39
|
mainsequence/instruments/__init__.py
|
40
|
+
mainsequence/instruments/instruments.default.toml
|
40
41
|
mainsequence/instruments/settings.py
|
41
42
|
mainsequence/instruments/utils.py
|
42
43
|
mainsequence/instruments/data_interface/__init__.py
|
@@ -1 +0,0 @@
|
|
1
|
-
from .instruments import *
|
@@ -1,10 +0,0 @@
|
|
1
|
-
from .data_interface import DateInfo, MockDataInterface, MSInterface
|
2
|
-
from mainsequence.instruments import settings
|
3
|
-
|
4
|
-
def _make_backend():
|
5
|
-
if getattr(settings, "data", None) and getattr(settings.data, "backend", "mock") == "mainsequence":
|
6
|
-
return MSInterface()
|
7
|
-
return MockDataInterface()
|
8
|
-
|
9
|
-
# export a single, uniform instance
|
10
|
-
data_interface = _make_backend()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/data_sources_interfaces/__init__.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/data_sources_interfaces/duckdb.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/client/data_sources_interfaces/timescale.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/assets/config.toml
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/assets/favicon.png
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/assets/logo.png
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/core/__init__.py
RENAMED
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/dashboards/streamlit/pages/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/__init__.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/base_instrument.py
RENAMED
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/european_option.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/json_codec.py
RENAMED
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/position.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/instruments/ql_fields.py
RENAMED
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/__init__.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/black_scholes.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/bond_pricer.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/instruments/pricing_models/swap_pricer.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/data_nodes/build_operations.py
RENAMED
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/tdag/data_nodes/persist_managers.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/agent_interface.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/config_handling.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/__init__.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/apps/news_app.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/contrib/prices/utils.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/notebook_handling.py
RENAMED
File without changes
|
{mainsequence-2.0.3 → mainsequence-2.0.4a0}/mainsequence/virtualfundbuilder/portfolio_interface.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|