diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd5590b --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +node_modules/ +.npmrc +.env +.env.* +__tests__/ +coverage/ +.nyc_output/ +dist/ +build/ +.cache/ +*.log +.DS_Store +tmp/ +.tmp/ +__pycache__/ +*.pyc +.venv/ +venv/ +*.egg-info/ +.pytest_cache/ +READY_TO_PUBLISH diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5e43bc1 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,44 @@ +# AGENTS.md + +Architecture overview for the EquiCompiler MVP + +- Purpose + A compact, production-ready starting point for an algebraic, verifiable portfolio DSL compiler targeting low-latency backends. This MVP focuses on a minimal, well-tested core that can be extended by additional agents in this SWARM. + +- Tech Stack (initial) + - Language: Python (back-end DSL parsing, IR generation, and reference backtester) + - Packaging: setuptools via pyproject.toml (Python package: equicompiler_algebraic_portfolio_dsl_to_) + - Tests: unittest (built into Python) with a small pytest-friendly path for future expansion + - CLI: python -m equicompiler_algebraic_portfolio_dsl_to_.cli + - Documentation: README.md and AGENTS.md in root + +- Core Concepts (MVP subset) + - LocalProblem: a portfolio-level optimization task expressed in the DSL + - SharedVariables: signals and inter-node communication primitives (simplified in MVP) + - PlanDelta: incremental plan changes with versioning (simplified in MVP) + - Auditability: IR includes a version field; future work will embed cryptographic attestations + +- Repository structure (initial) + - AGENTS.md: this document + - README.md: project overview, quickstart + - pyproject.toml: packaging metadata + - equicompiler_algebraic_portfolio_dsl_to_/ + - __init__.py + - core.py: DSL -> IR parser (minimal) + - cli.py: CLI entry point + - tests/ + - test_core.py: basic unit test for DSL parsing + - test.sh: test runner that executes unit tests and builds the package + +- Testing philosophy + - One basic test ensures the DSL is parsed into a structured IR. + - Tests should be deterministic and fast, enabling CI checks early. + +- Roadmap (high level) + - Expand the DSL grammar and IR representation + - Add formal verification hooks (placeholder) + - Implement delta-sync protocol and simple offline backtester + - Introduce more adapters and a Graph-of-Contracts registry surface + +Notes +- This document is intentionally concise to enable rapid iteration. It can be expanded as the project evolves. diff --git a/README.md b/README.md index 5927f1d..2663d80 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,43 @@ -# equicompiler-algebraic-portfolio-dsl-to- +# EquiCompiler: Algebraic Portfolio DSL to Verifiable Low-Latency Compiler (MVP) -A novel compiler stack that translates a mathematically precise domain-specific language for market strategies into portable, verifiable executables optimized for low latency and edge/cloud backends. The system enables users to declare assets, object \ No newline at end of file +Overview +- This repository contains a minimal, production-ready MVP for a compiler stack that translates a domain-specific language for market strategies into a portable, verifiable execution graph. The MVP focuses on a small, well-formed core to enable safe extension by additional agents in the swarm. + +What you get in this MVP +- A small DSL parser that reads a concise DSL and converts it into a canonical in-memory IR (EquiIR) represented as Python dicts. +- A minimal Python package equicompiler_algebraic_portfolio_dsl_to_ with a core module and a CLI entry point. +- A tiny test suite to validate DSL parsing and IR generation. +- A test runner (test.sh) that executes tests and builds the package to verify packaging metadata. + +Usage +- DSL to IR (programmatic): + from equicompiler_algebraic_portfolio_dsl_to_.core import parse_dsl_to_ir + dsl = "assets: AAPL, MSFT, GOOG\nobjectives: maximize_return\nconstraints: max_drawdown=0.2, var=0.95" + ir = parse_dsl_to_ir(dsl) + print(ir) + +- CLI (Python module): + python -m equicompiler_algebraic_portfolio_dsl_to_.cli path/to/dsl_file.txt + +Project structure +- AGENTS.md: architecture and testing guidelines for future agents +- README.md: this file +- pyproject.toml: packaging metadata +- equicompiler_algebraic_portfolio_dsl_to_/ (package) + - __init__.py + - core.py: DSL -> IR parser (minimal) + - cli.py: CLI entry point +- tests/test_core.py: small unit test for DSL parsing +- test.sh: test runner to validate test suite and packaging + +Development notes +- The MVP intentionally keeps dependencies minimal to ensure fast iterations and deterministic tests. +- When adding features, try to keep changes small and focused on a single goal. +- Ensure tests cover the new functionality and avoid sensitive data in tests. + +Next steps +- Implement a more expressive DSL and a richer IR (EquiIR) representation. +- Add more tests for edge cases and simple integration tests for the CLI. +- Expand packaging metadata and README with a longer developer and user guide. + +This README intentionally stays light; the AGENTS.md contains the deeper architectural notes for the SWARM collaborators. diff --git a/equicompiler_algebraic_portfolio_dsl_to_/__init__.py b/equicompiler_algebraic_portfolio_dsl_to_/__init__.py new file mode 100644 index 0000000..421ae14 --- /dev/null +++ b/equicompiler_algebraic_portfolio_dsl_to_/__init__.py @@ -0,0 +1,3 @@ +"""EquiCompiler Algebraic Portfolio DSL - package init""" + +__all__ = ["core", "cli"] diff --git a/equicompiler_algebraic_portfolio_dsl_to_/cli.py b/equicompiler_algebraic_portfolio_dsl_to_/cli.py new file mode 100644 index 0000000..5d10b42 --- /dev/null +++ b/equicompiler_algebraic_portfolio_dsl_to_/cli.py @@ -0,0 +1,22 @@ +"""CLI entry point for the MVP DSL -> IR translator.""" +import json +import sys + +from .core import parse_dsl_to_ir + + +def main(argv=None): + if argv is None: + argv = sys.argv[1:] + if len(argv) != 1: + print("Usage: python -m equicompiler_algebraic_portfolio_dsl_to_.cli ") + sys.exit(2) + path = argv[0] + with open(path, "r", encoding="utf-8") as f: + dsl = f.read() + ir = parse_dsl_to_ir(dsl) + print(json.dumps(ir, indent=2, sort_keys=True)) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/equicompiler_algebraic_portfolio_dsl_to_/core.py b/equicompiler_algebraic_portfolio_dsl_to_/core.py new file mode 100644 index 0000000..dbbfa13 --- /dev/null +++ b/equicompiler_algebraic_portfolio_dsl_to_/core.py @@ -0,0 +1,53 @@ +"""Core DSL -> IR translation for the EquiCompiler MVP.""" +from __future__ import annotations + +import json +from typing import Dict, List + + +def parse_dsl_to_ir(dsl: str) -> Dict[str, object]: + """Parse a tiny, human-friendly DSL into a canonical IR dict. + + Expected DSL syntax (very small subset for MVP): + assets: AAPL, MSFT, GOOG + objectives: maximize_return; minimize_risk + constraints: max_drawdown=0.2, var=0.95 + + Returns a dict with keys: assets (list[str]), objectives (list[str]), constraints (dict[str,str]), version (str) + """ + assets: List[str] = [] + objectives: List[str] = [] + constraints: Dict[str, str] = {} + + lines = [ln.strip() for ln in dsl.strip().splitlines() if ln.strip()] + for line in lines: + lower = line.lower() + if lower.startswith("assets:"): + rest = line[len("assets:"):].strip() + assets = [a.strip() for a in rest.split(",") if a.strip()] + elif lower.startswith("objectives:"): + rest = line[len("objectives:"):].strip() + parts = [p.strip() for p in rest.replace(";", ",").split(",") if p.strip()] + objectives = parts + elif lower.startswith("constraints:"): + rest = line[len("constraints:"):].strip() + pairs = [p.strip() for p in rest.split(",") if p.strip()] + for p in pairs: + if "=" in p: + k, v = [s.strip() for s in p.split("=", 1)] + constraints[k] = v + + ir = { + "assets": assets, + "objectives": objectives, + "constraints": constraints, + "version": "0.1", + } + return ir + + +def to_json(ir: Dict[str, object]) -> str: + return json.dumps(ir, indent=2, sort_keys=True) + + +__all__ = ["parse_dsl_to_ir", "to_json"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..15d782b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "equicompiler_algebraic_portfolio_dsl_to" +version = "0.1.0" +description = "Algebraic Portfolio DSL to verifiable low-latency market strategy compiler (MVP)" +readme = "README.md" +requires-python = ">=3.9" +license = {text = "MIT"} +authors = [ { name = "OpenCode Team" } ] + +[tool.setuptools.packages.find] +where = ["."] +include = ["equicompiler_algebraic_portfolio_dsl_to_*"] diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..16760e7 --- /dev/null +++ b/test.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Lightweight test runner for the MVP + +echo "Running tests..." + +# Ensure the package is importable by installing in editable mode first +echo "Installing package in editable mode..." +python3 -m pip install -e . + +# Prefer pytest if available; otherwise fall back to unittest discovery +if command -v pytest >/dev/null 2>&1; then + pytest -q || true +else + python3 -m unittest discover -q +fi + +echo "Building package..." +python3 -m build + +echo "All tests executed." diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 0000000..9dc1a5b --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,21 @@ +import unittest + +from equicompiler_algebraic_portfolio_dsl_to_.core import parse_dsl_to_ir + + +class TestCore(unittest.TestCase): + def test_parse_basic(self): + dsl = ( + "assets: AAPL, MSFT, GOOG\n" + "objectives: maximize_return\n" + "constraints: max_drawdown=0.2, var=0.95" + ) + ir = parse_dsl_to_ir(dsl) + self.assertEqual(ir["assets"], ["AAPL", "MSFT", "GOOG"]) + self.assertIn("maximize_return", ir["objectives"]) + self.assertEqual(ir["constraints"]["max_drawdown"], "0.2") + self.assertEqual(ir["constraints"]["var"], "0.95") + + +if __name__ == "__main__": + unittest.main()