Skip to main content

MIF-DAL — Data Abstraction Layer

tests version python license

mif-dal is the data assembly layer of the MIF ecosystem. It fetches OHLCV market data from external sources, certifies it through mif-dqf, and delivers an immutable, hash-anchored result ready for metric computation.


Why mif-dal?

Quantitative research fails silently when its data foundation is uncertain. A strategy that looks profitable on Yahoo Finance data may behave differently on Kraken data — same asset, different gaps, different fills, different hashes.

mif-dal makes data provenance explicit and mandatory:

  • Every stream carries a assembly_hash (SHA-256 of raw bytes before any transformation). Two calls with the same parameters produce the same hash, or the difference is auditable.
  • Physical validity is guaranteed by mif-dqf before any data reaches your computation layer.
  • Source fallback is recorded, not hidden. If Kraken was unavailable and Yahoo was used instead, that decision is in the source_manifest.
  • The output — DALHandoff — is frozen. It cannot be mutated after emission.

The MIF Ecosystem

External data sources
        ↓
[mif-dal]   assembles stream, computes assembly_hash, delegates to mif-dqf
        ↓ DALHandoff
[mif-dqf]   certifies physical validity (OHLCV physics, calendar, gaps)
        ↓ DQFReport embedded in DALHandoff
[mif-core]  certifies metric/signal integrity (planned)
        ↓ MIFCertification
[QAAF Studio]  research layer (QS-PAF, QS-MÉTIS)

mif-dal sits between your data sources and your computation. It does not evaluate strategies. It does not qualify asset pairs. It answers one question: "Can I assemble a reproducible, certified OHLCV stream from available sources for this asset and date range?"


Installation

pip install mif-dal

Requires Python 3.11+ and mif-dqf >= 1.2.0 (installed automatically).

Optional: Dukascopy adapter

The Dukascopy adapter requires Node.js and dukascopy-node:

npm install -g dukascopy-node

Quick Start

from dal import DAL, DALConfig
from dal.adapters import KrakenAdapter, YahooAdapter

config = DALConfig()
dal = DAL(config, sources=(KrakenAdapter(), YahooAdapter()))

# One call per asset — caller composes the pair (architectural decision D-DAL-007)
h_paxg = dal.get_certified_stream(
    asset_id="PAXG-USD",
    source_preference=["kraken", "yahoo"],
    start="2024-01-01",
    end="2024-12-31",
    calendar="CRYPTO_247",
    dqf_version_target="1.2.0",
)

h_btc = dal.get_certified_stream(
    asset_id="BTC-USD",
    source_preference=["kraken", "yahoo"],
    start="2024-01-01",
    end="2024-12-31",
    calendar="CRYPTO_247",
    dqf_version_target="1.2.0",
)

# Caller constructs the ratio
prices_pair = h_paxg.stream["close"] / h_btc.stream["close"]

print(f"DQF status : {h_paxg.dqf_status} / {h_btc.dqf_status}")
print(f"AQI        : {h_paxg.aqi:.0f} / {h_btc.aqi:.0f}")
print(f"Hash PAXG  : {h_paxg.assembly_hash[:16]}...")
print(f"Hash BTC   : {h_btc.assembly_hash[:16]}...")

Diagnostic mode (exploratory, no version enforcement)

h = dal.get_diagnostic_stream(
    asset_id="BTC-USD",
    source_preference=["yahoo"],
    start="2023-01-01",
    end="2023-12-31",
    calendar="CRYPTO_247",
)
print(h.dqf_report)

The DALHandoff Object

Every successful call returns a DALHandoff — a frozen dataclass with 15 fields:

Field Type Description
stream pd.DataFrame OHLCV, UTC DatetimeIndex, no NaN, sorted ascending
asset_id str e.g. "PAXG-USD"
calendar str e.g. "CRYPTO_247", "NYSE"
assembly_hash str SHA-256 of raw bytes before any transformation
handoff_timestamp datetime UTC emission time
dal_version str mif-dal package version
source_manifest tuple Immutable record of sources used and fallback chain
coverage str FULL / PARTIAL / DEGRADED
truncated_days int 0 if FULL
dqf_status str PASS or WARNING
dqf_mpi float MIF Purity Index 0–100 (from mif-dqf)
dqf_version str mif-dqf version used
dqf_version_target str Minimum version declared by caller
dqf_report DQFReport Full mif-dqf report
aqi float Assembly Quality Index 0–100

DALHandoff is frozen=True. It cannot be mutated after emission.


Assembly Quality Index (AQI)

AQI measures how much intervention was required to assemble the stream. 100 = preferred source, full range, no retries. Lower = more intervention.

AQI Label Meaning
100 EXCELLENT Preferred source, full range, no retries
80–99 GOOD Minor fallback or single retry
60–79 ADVISORY Fallback + partial range
< 60 REVIEW Heavy intervention — investigate

AQI is on the D-SIG Standard v0.5 0–100 scale and can be used directly as a dimensions entry in a D-SIG signal.


Available Sources

Source Adapter Assets Notes
Kraken KrakenAdapter Crypto pairs Data available ~last 12 months
Yahoo Finance YahooAdapter Equities, ETFs, Crypto Broad coverage, variable quality
Dukascopy DukascopyAdapter Forex, Crypto Requires dukascopy-node
In-memory InMemorySource Any Testing and research

Error Handling

from dal.exceptions import DALHandoffError, DALVersionError, DALConfigError

try:
    h = dal.get_certified_stream(...)
except DALConfigError as e:
    # Missing or invalid configuration (e.g. calendar omitted)
    print(e)
except DALVersionError as e:
    # Installed mif-dqf < dqf_version_target
    print(e)
except DALHandoffError as e:
    # DQF returned VOID, or all sources failed
    print(e.reason)          # "DQF_VOID" | "ALL_SOURCES_FAILED"
    print(e.source_failures) # list of per-source error details

Errors are atomic: either a complete DALHandoff is returned, or an exception is raised. There is no partial or degraded return value.


Development

git clone https://github.com/symbioticode/mif-dal.git
cd mif-dal
uv sync --extra dev
./scripts/dev.sh check   # Ruff + Mypy + Pytest

mif-dal does not ship a flake.nix at this stage, unlike mif-dqf — this is a deliberate scope decision, not an oversight.

Running tests

# Without network (fast, CI-suitable)
pytest tests/ -q

# With real network (Kraken, Yahoo, Dukascopy)
pytest tests/ --run-network

Validation

python scripts/adversarial_dal_check_p3.py    # Adversarial suite (65 checks)

Documentation

Document Description
docs/API.md Full public API reference
docs/ARCHITECTURE.md Pipeline, decisions, component map
TROUBLESHOOTING.md Common issues (Kraken limits, NixOS, Dukascopy)
docs/DAL_SPECIFICATION_v1.0.md Formal specification — source of truth

Relationship to mif-dqf

mif-dal depends on mif-dqf for physical data validation. mif-dal calls mif-dqf internally — you do not need to call mif-dqf directly when using mif-dal.

The assembly_hash computed by mif-dal is passed to mif-dqf as raw_data_hash, so both layers anchor on the same SHA-256 value. The MIF-UID produced by mif-dqf is included in DALHandoff.dqf_report.

Revalidating a certification manually, outside mif-dal

If you hold a DALHandoff and want to revalidate it independently by calling mif-dqf directly (rather than going back through mif-dal), you must pass raw_data_hash=handoff.assembly_hash explicitly:

from dqf import DQFConfig, DQFMode, DQFValidator

validator = DQFValidator(DQFConfig(mode=DQFMode.CERTIFICATION))

report = validator.validate(
    handoff.stream,
    calendar=handoff.calendar,
    raw_data_hash=handoff.assembly_hash,  # required to reproduce the same MIF-UID
)

assert report.mif_uid == handoff.dqf_report.mif_uid

Warning: mif-dal's assembly_hash and mif-dqf's self-computed default hash use two different, incompatible algorithms (different serialization, different output format). If you omit raw_data_hash, mif-dqf silently computes its own hash instead of raising an error — the call succeeds, but it produces a different MIF-UID than the one in the original DALHandoff.dqf_report, with no warning that anything went wrong. Always pass raw_data_hash=handoff.assembly_hash when revalidating outside mif-dal.


License

MIT — see LICENSE.

Part of the MIF ecosystem by symbioticode.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mif_dal-0.2.0.tar.gz (86.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mif_dal-0.2.0-py3-none-any.whl (28.3 kB view details)

Uploaded Python 3

File details

Details for the file mif_dal-0.2.0.tar.gz.

File metadata

  • Download URL: mif_dal-0.2.0.tar.gz
  • Upload date:
  • Size: 86.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for mif_dal-0.2.0.tar.gz
Algorithm Hash digest
SHA256 162700e99f0b5e4d34d538cdc8132567c9ac4f05b5f672b19defd16bdc8ce126
MD5 c2eae98495ab9291451e00908bc404b4
BLAKE2b-256 e7b01e44eaff9f38a79376cc7e3b4edcaa5e3a5d2b17f97584b0cc7b3c40b351

See more details on using hashes here.

Provenance

The following attestation bundles were made for mif_dal-0.2.0.tar.gz:

Publisher: mif-dal-publish.yml on symbioticode/mif-dal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mif_dal-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: mif_dal-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 28.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for mif_dal-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 628570a0660b64f527951ce62f82accdd210ab0b6042fe73aa1fe0f44af103be
MD5 af7559dcda81678ed2794ad8c72ad928
BLAKE2b-256 c0906be1fd43431cae1561302af18c7dae53e7a6cfdb23a0c5c8b8e016acb3cf

See more details on using hashes here.

Provenance

The following attestation bundles were made for mif_dal-0.2.0-py3-none-any.whl:

Publisher: mif-dal-publish.yml on symbioticode/mif-dal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page