Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,92 @@ $RECYCLE.BIN/
# =========================
# Operating System Files
# =========================

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Virtual environments
venv/
ENV/
env/
.venv/
.env

# Testing
.pytest_cache/
.coverage
.coverage.*
htmlcov/
coverage.xml
*.cover
*.py,cover
.hypothesis/
.tox/
nosetests.xml
coverage/
*.log

# IDE
.idea/
.vscode/
*.swp
*.swo
*~
.project
.pydevproject
.settings/

# Claude
.claude/*

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
2,781 changes: 2,781 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
[tool.poetry]
name = "python-trading-algorithms"
version = "0.1.0"
description = "Python trading algorithms and financial analysis examples"
authors = ["Your Name <you@example.com>"]
readme = "README.md"
packages = [{include = "Chapter7"}, {include = "Chapter8"}]

[tool.poetry.extras]
fix = ["quickfix"]

[tool.poetry.dependencies]
python = "^3.8.1"
pandas = "^2.0.0"
numpy = "^1.24.0"
matplotlib = "^3.7.0"
pandas-datareader = "^0.10.0"
scikit-learn = "^1.3.0"
quickfix = {version = "^1.15.1", optional = true}
twisted = "^23.10.0"
pyyaml = "^6.0"

[tool.poetry.group.dev.dependencies]
pytest = "^7.4.0"
pytest-cov = "^4.1.0"
pytest-mock = "^3.12.0"
black = "^23.0.0"
flake8 = "^6.0.0"

[tool.poetry.scripts]
test = "pytest:main"
tests = "pytest:main"

[tool.pytest.ini_options]
minversion = "7.0"
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py", "*_tests.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--verbose",
"--tb=short",
"--cov=.",
"--cov-branch",
"--cov-report=term-missing:skip-covered",
"--cov-report=html:htmlcov",
"--cov-report=xml:coverage.xml",
"--cov-fail-under=80",
]
markers = [
"unit: Unit tests",
"integration: Integration tests",
"slow: Slow running tests",
]
filterwarnings = [
"error",
"ignore::UserWarning",
"ignore::DeprecationWarning",
]

[tool.coverage.run]
source = ["."]
omit = [
"*/tests/*",
"*/test_*",
"*/__pycache__/*",
"*/venv/*",
"*/.venv/*",
"*/site-packages/*",
"setup.py",
"*/migrations/*",
"*/__init__.py",
]

[tool.coverage.report]
precision = 2
show_missing = true
skip_covered = false
skip_empty = true
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]

[tool.coverage.html]
directory = "htmlcov"

[tool.coverage.xml]
output = "coverage.xml"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Tests package initialization
112 changes: 112 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"""
Shared pytest fixtures and configuration for all tests.
"""
import pytest
import tempfile
import shutil
from pathlib import Path
from unittest.mock import Mock, MagicMock
import pandas as pd
import numpy as np


@pytest.fixture
def temp_dir():
"""Create a temporary directory for test files."""
temp_path = tempfile.mkdtemp()
yield Path(temp_path)
shutil.rmtree(temp_path)


@pytest.fixture
def mock_config():
"""Provide a mock configuration object."""
config = Mock()
config.debug = False
config.log_level = "INFO"
config.data_dir = "/tmp/test_data"
return config


@pytest.fixture
def sample_dataframe():
"""Create a sample pandas DataFrame for testing."""
dates = pd.date_range(start='2023-01-01', end='2023-01-10', freq='D')
data = {
'Open': np.random.uniform(100, 110, len(dates)),
'High': np.random.uniform(110, 120, len(dates)),
'Low': np.random.uniform(90, 100, len(dates)),
'Close': np.random.uniform(95, 115, len(dates)),
'Volume': np.random.randint(1000000, 5000000, len(dates))
}
df = pd.DataFrame(data, index=dates)
return df


@pytest.fixture
def mock_market_data():
"""Mock market data provider."""
mock = MagicMock()
mock.get_historical_data.return_value = pd.DataFrame({
'Close': [100, 101, 99, 102, 103],
'Volume': [1000000, 1100000, 900000, 1200000, 1050000]
})
return mock


@pytest.fixture
def mock_order():
"""Create a mock order object."""
order = Mock()
order.symbol = "AAPL"
order.quantity = 100
order.price = 150.0
order.side = "BUY"
order.order_type = "LIMIT"
order.status = "PENDING"
return order


@pytest.fixture
def mock_portfolio():
"""Create a mock portfolio object."""
portfolio = Mock()
portfolio.cash = 100000.0
portfolio.positions = {}
portfolio.get_total_value = Mock(return_value=100000.0)
portfolio.get_position = Mock(return_value=0)
return portfolio


@pytest.fixture(autouse=True)
def reset_random_seed():
"""Reset random seeds for reproducible tests."""
np.random.seed(42)
import random
random.seed(42)


@pytest.fixture
def captured_logs(caplog):
"""Fixture to capture log messages."""
with caplog.at_level("DEBUG"):
yield caplog


@pytest.fixture
def mock_file_system(mocker):
"""Mock file system operations."""
mock_open = mocker.mock_open(read_data="test data")
mocker.patch("builtins.open", mock_open)
return mock_open


@pytest.fixture
def clean_imports(monkeypatch):
"""Clean module imports between tests."""
import sys
modules_backup = sys.modules.copy()
yield
# Restore original modules
sys.modules.clear()
sys.modules.update(modules_backup)
1 change: 1 addition & 0 deletions tests/integration/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Integration tests package
Loading