[project] name = "arbitrage" version = "0.1.0" description = "Polymarket NegRisk multi-outcome arbitrage scanner & executor (paper + live)" requires-python = ">=3.12" readme = "README.md" dependencies = [ # Polymarket / chain "py-clob-client>=0.20.0", "web3>=7.0.0", "eth-account>=0.13.0", # Async IO "httpx>=0.27.0", "websockets>=13.0", "tenacity>=9.0.0", # Web UI "fastapi>=0.115.0", "uvicorn[standard]>=0.32.0", "jinja2>=3.1.4", "sse-starlette>=2.1.0", # Persistence "aiosqlite>=0.20.0", # Sorted price ladders for the L2 book "sortedcontainers>=2.4.0", # Config / models / logs "pydantic>=2.9.0", "pydantic-settings>=2.5.0", "loguru>=0.7.2", "python-dotenv>=1.0.1", "orjson>=3.10.0", ] [project.optional-dependencies] dev = [ "pytest>=8.3.0", "pytest-asyncio>=0.24.0", "pytest-cov>=5.0.0", "ruff>=0.7.0", "mypy>=1.13.0", "respx>=0.21.0", "freezegun>=1.5.0", ] [project.scripts] arb = "arbitrage.cli:main" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["arbitrage"] [tool.pytest.ini_options] asyncio_mode = "auto" testpaths = ["tests"] addopts = "-ra --strict-markers --strict-config" [tool.ruff] line-length = 100 target-version = "py312" [tool.ruff.lint] select = ["E", "F", "I", "N", "B", "UP", "SIM", "RUF", "ASYNC"] ignore = [ "E501", # line length handled by formatter "N817", # `Decimal as D` alias is an intentional test convention "UP042", # str+Enum is fine; migrating to StrEnum is cosmetic "N818", # RiskDenied is a flow-control exception, Error suffix unneeded "SIM105", # try/except/pass reads fine for cancellation suppression "SIM118", # x in dict.keys() is explicit; not always a win to remove ] [tool.ruff.lint.per-file-ignores] "tests/*" = ["F401"] # test fixtures commonly import for side effects [tool.mypy] python_version = "3.12" strict = true warn_return_any = true warn_unused_ignores = true plugins = ["pydantic.mypy"]