deltafq 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl

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.

Potentially problematic release.


This version of deltafq might be problematic. Click here for more details.

Files changed (60) hide show
  1. deltafq/__init__.py +30 -31
  2. deltafq/backtest/__init__.py +17 -7
  3. deltafq/backtest/engine.py +99 -52
  4. deltafq/backtest/metrics.py +113 -0
  5. deltafq/backtest/performance.py +81 -0
  6. deltafq/backtest/reporter.py +91 -0
  7. deltafq/core/__init__.py +19 -0
  8. deltafq/core/base.py +37 -0
  9. deltafq/core/config.py +63 -0
  10. deltafq/core/exceptions.py +35 -0
  11. deltafq/core/logger.py +46 -0
  12. deltafq/data/__init__.py +17 -7
  13. deltafq/data/cleaner.py +41 -0
  14. deltafq/data/fetcher.py +52 -0
  15. deltafq/data/storage.py +56 -0
  16. deltafq/data/validator.py +52 -0
  17. deltafq/indicators/__init__.py +17 -8
  18. deltafq/indicators/momentum.py +56 -23
  19. deltafq/indicators/technical.py +59 -0
  20. deltafq/indicators/trend.py +129 -61
  21. deltafq/indicators/volatility.py +67 -27
  22. deltafq/live/__init__.py +17 -0
  23. deltafq/live/connection.py +235 -0
  24. deltafq/live/data_feed.py +159 -0
  25. deltafq/live/monitoring.py +192 -0
  26. deltafq/live/risk_control.py +193 -0
  27. deltafq/strategy/__init__.py +17 -6
  28. deltafq/strategy/base_strategy.py +53 -0
  29. deltafq/strategy/portfolio.py +82 -0
  30. deltafq/strategy/risk_manager.py +64 -0
  31. deltafq/strategy/signal_generator.py +52 -0
  32. deltafq/trading/__init__.py +19 -0
  33. deltafq/trading/broker.py +119 -0
  34. deltafq/trading/execution.py +176 -0
  35. deltafq/trading/order_manager.py +111 -0
  36. deltafq/trading/position_manager.py +157 -0
  37. deltafq/trading/simulator.py +150 -0
  38. deltafq-0.1.2.dist-info/METADATA +110 -0
  39. deltafq-0.1.2.dist-info/RECORD +43 -0
  40. deltafq-0.1.2.dist-info/entry_points.txt +2 -0
  41. {deltafq-0.1.1.dist-info → deltafq-0.1.2.dist-info}/licenses/LICENSE +21 -22
  42. deltafq/backtest/result.py +0 -45
  43. deltafq/data/base.py +0 -30
  44. deltafq/data/loader.py +0 -63
  45. deltafq/optimization/__init__.py +0 -6
  46. deltafq/optimization/grid_search.py +0 -41
  47. deltafq/performance/__init__.py +0 -6
  48. deltafq/performance/metrics.py +0 -37
  49. deltafq/risk/__init__.py +0 -7
  50. deltafq/risk/metrics.py +0 -33
  51. deltafq/risk/position.py +0 -39
  52. deltafq/strategy/base.py +0 -44
  53. deltafq/trade/__init__.py +0 -6
  54. deltafq/trade/broker.py +0 -40
  55. deltafq/utils/__init__.py +0 -6
  56. deltafq/utils/time.py +0 -32
  57. deltafq-0.1.1.dist-info/METADATA +0 -202
  58. deltafq-0.1.1.dist-info/RECORD +0 -29
  59. {deltafq-0.1.1.dist-info → deltafq-0.1.2.dist-info}/WHEEL +0 -0
  60. {deltafq-0.1.1.dist-info → deltafq-0.1.2.dist-info}/top_level.txt +0 -0
deltafq/__init__.py CHANGED
@@ -1,31 +1,30 @@
1
- """DeltaFQ - 专业的Python量化交易库
2
-
3
- 一个面向量化策略开发者和量化研究人员的完整工具链。
4
- """
5
-
6
- __version__ = "0.1.1"
7
- __author__ = "DeltaFQ Team"
8
-
9
- # 导入主要模块
10
- from deltafq import data
11
- from deltafq import indicators
12
- from deltafq import strategy
13
- from deltafq import backtest
14
- from deltafq import risk
15
- from deltafq import performance
16
- from deltafq import optimization
17
- from deltafq import trade
18
- from deltafq import utils
19
-
20
- __all__ = [
21
- "data",
22
- "indicators",
23
- "strategy",
24
- "backtest",
25
- "risk",
26
- "performance",
27
- "optimization",
28
- "trade",
29
- "utils",
30
- ]
31
-
1
+ """
2
+ DeltaFQ - A comprehensive Python quantitative finance library.
3
+
4
+ This library provides tools for strategy development, backtesting,
5
+ paper trading, and live trading.
6
+ """
7
+
8
+ __version__ = "0.1.0"
9
+ __author__ = "DeltaF"
10
+
11
+ # Import core modules
12
+ from . import core
13
+ from . import data
14
+ from . import strategy
15
+ from . import backtest
16
+ from . import indicators
17
+ from . import trading
18
+ from . import live
19
+
20
+ __all__ = [
21
+ "core",
22
+ "data",
23
+ "strategy",
24
+ "backtest",
25
+ "indicators",
26
+ "trading",
27
+ "live"
28
+ ]
29
+
30
+
@@ -1,7 +1,17 @@
1
- """回测引擎模块"""
2
-
3
- from deltafq.backtest.engine import BacktestEngine
4
- from deltafq.backtest.result import BacktestResult
5
-
6
- __all__ = ["BacktestEngine", "BacktestResult"]
7
-
1
+ """
2
+ Backtesting module for DeltaFQ.
3
+ """
4
+
5
+ from .engine import BacktestEngine
6
+ from .performance import PerformanceAnalyzer
7
+ from .metrics import MetricsCalculator
8
+ from .reporter import BacktestReporter
9
+
10
+ __all__ = [
11
+ "BacktestEngine",
12
+ "PerformanceAnalyzer",
13
+ "MetricsCalculator",
14
+ "BacktestReporter"
15
+ ]
16
+
17
+
@@ -1,52 +1,99 @@
1
- """回测引擎"""
2
-
3
- import pandas as pd
4
- from typing import Optional
5
- from deltafq.strategy.base import Strategy
6
- from deltafq.backtest.result import BacktestResult
7
-
8
-
9
- class BacktestEngine:
10
- """回测引擎"""
11
-
12
- def __init__(
13
- self,
14
- initial_cash: float = 100000,
15
- commission: float = 0.0003,
16
- slippage: float = 0.0
17
- ):
18
- """初始化回测引擎
19
-
20
- Args:
21
- initial_cash: 初始资金
22
- commission: 手续费率
23
- slippage: 滑点
24
- """
25
- self.initial_cash = initial_cash
26
- self.commission = commission
27
- self.slippage = slippage
28
-
29
- def run(
30
- self,
31
- data: pd.DataFrame,
32
- strategy: Strategy
33
- ) -> BacktestResult:
34
- """运行回测
35
-
36
- Args:
37
- data: 历史数据
38
- strategy: 策略实例
39
-
40
- Returns:
41
- 回测结果
42
- """
43
- for idx, bar in data.iterrows():
44
- strategy.on_bar(bar)
45
-
46
- result = BacktestResult(
47
- initial_cash=self.initial_cash,
48
- data=data,
49
- signals=strategy.get_signals()
50
- )
51
- return result
52
-
1
+ """
2
+ Backtesting engine for DeltaFQ.
3
+ """
4
+
5
+ import pandas as pd
6
+ from typing import Dict, Any, Optional
7
+ from ..core.base import BaseComponent
8
+ from ..core.exceptions import BacktestError
9
+
10
+
11
+ class BacktestEngine(BaseComponent):
12
+ """Backtesting engine for strategy testing."""
13
+
14
+ def __init__(self, initial_capital: float = 100000, commission: float = 0.001, **kwargs):
15
+ """Initialize backtest engine."""
16
+ super().__init__(**kwargs)
17
+ self.initial_capital = initial_capital
18
+ self.commission = commission
19
+ self.results = None
20
+
21
+ def initialize(self) -> bool:
22
+ """Initialize backtest engine."""
23
+ self.logger.info(f"Initializing backtest engine with capital: {self.initial_capital}")
24
+ return True
25
+
26
+ def run_backtest(self, strategy, data: pd.DataFrame) -> Dict[str, Any]:
27
+ """Run backtest for given strategy and data."""
28
+ try:
29
+ self.logger.info("Starting backtest")
30
+
31
+ # Initialize portfolio
32
+ cash = self.initial_capital
33
+ positions = {}
34
+ trades = []
35
+
36
+ # Run strategy on data
37
+ for i, (date, row) in enumerate(data.iterrows()):
38
+ # Get signals from strategy
39
+ signals = strategy.generate_signals(data.iloc[:i+1])
40
+
41
+ if not signals.empty and i > 0:
42
+ signal = signals.iloc[-1]
43
+
44
+ # Execute trades based on signals
45
+ if signal != 0: # Buy or sell signal
46
+ symbol = 'STOCK' # Simplified for single asset
47
+ price = row['close']
48
+ quantity = int(signal * cash * 0.1 / price) # Use 10% of cash
49
+
50
+ if quantity > 0 and quantity * price <= cash:
51
+ # Buy
52
+ cost = quantity * price * (1 + self.commission)
53
+ cash -= cost
54
+ positions[symbol] = positions.get(symbol, 0) + quantity
55
+ trades.append({
56
+ 'date': date,
57
+ 'symbol': symbol,
58
+ 'quantity': quantity,
59
+ 'price': price,
60
+ 'type': 'buy'
61
+ })
62
+ elif quantity < 0 and positions.get(symbol, 0) >= abs(quantity):
63
+ # Sell
64
+ quantity = abs(quantity)
65
+ proceeds = quantity * price * (1 - self.commission)
66
+ cash += proceeds
67
+ positions[symbol] -= quantity
68
+ trades.append({
69
+ 'date': date,
70
+ 'symbol': symbol,
71
+ 'quantity': -quantity,
72
+ 'price': price,
73
+ 'type': 'sell'
74
+ })
75
+
76
+ # Calculate final portfolio value
77
+ final_price = data['close'].iloc[-1]
78
+ final_value = cash + sum(positions.values()) * final_price
79
+
80
+ self.results = {
81
+ 'initial_capital': self.initial_capital,
82
+ 'final_value': final_value,
83
+ 'total_return': (final_value - self.initial_capital) / self.initial_capital,
84
+ 'trades': trades,
85
+ 'final_positions': positions,
86
+ 'final_cash': cash
87
+ }
88
+
89
+ self.logger.info(f"Backtest completed. Total return: {self.results['total_return']:.2%}")
90
+ return self.results
91
+
92
+ except Exception as e:
93
+ raise BacktestError(f"Backtest failed: {str(e)}")
94
+
95
+ def get_results(self) -> Optional[Dict[str, Any]]:
96
+ """Get backtest results."""
97
+ return self.results
98
+
99
+
@@ -0,0 +1,113 @@
1
+ """
2
+ Backtest metrics calculation.
3
+ """
4
+
5
+ import pandas as pd
6
+ import numpy as np
7
+ from typing import Dict, Any
8
+ from ..core.base import BaseComponent
9
+
10
+
11
+ class MetricsCalculator(BaseComponent):
12
+ """Calculate various backtest metrics."""
13
+
14
+ def initialize(self) -> bool:
15
+ """Initialize metrics calculator."""
16
+ self.logger.info("Initializing metrics calculator")
17
+ return True
18
+
19
+ def calculate_trade_metrics(self, trades: list) -> Dict[str, Any]:
20
+ """Calculate trade-based metrics."""
21
+ if not trades:
22
+ return {}
23
+
24
+ trade_df = pd.DataFrame(trades)
25
+
26
+ # Separate buy and sell trades
27
+ buy_trades = trade_df[trade_df['type'] == 'buy']
28
+ sell_trades = trade_df[trade_df['type'] == 'sell']
29
+
30
+ # Calculate P&L for each trade (simplified)
31
+ pnl = []
32
+ for _, sell_trade in sell_trades.iterrows():
33
+ # Find corresponding buy trade
34
+ buy_trade = buy_trades[buy_trades['symbol'] == sell_trade['symbol']].iloc[0]
35
+ trade_pnl = (sell_trade['price'] - buy_trade['price']) * sell_trade['quantity']
36
+ pnl.append(trade_pnl)
37
+
38
+ if pnl:
39
+ pnl_series = pd.Series(pnl)
40
+ return {
41
+ 'total_trades': len(pnl),
42
+ 'winning_trades': (pnl_series > 0).sum(),
43
+ 'losing_trades': (pnl_series < 0).sum(),
44
+ 'win_rate': (pnl_series > 0).mean(),
45
+ 'avg_win': pnl_series[pnl_series > 0].mean() if (pnl_series > 0).any() else 0,
46
+ 'avg_loss': pnl_series[pnl_series < 0].mean() if (pnl_series < 0).any() else 0,
47
+ 'total_pnl': pnl_series.sum()
48
+ }
49
+
50
+ return {}
51
+
52
+ def calculate_risk_metrics(self, returns: pd.Series) -> Dict[str, float]:
53
+ """Calculate risk-related metrics."""
54
+ if len(returns) == 0:
55
+ return {}
56
+
57
+ # Value at Risk (VaR)
58
+ var_95 = np.percentile(returns, 5)
59
+ var_99 = np.percentile(returns, 1)
60
+
61
+ # Conditional Value at Risk (CVaR)
62
+ cvar_95 = returns[returns <= var_95].mean()
63
+ cvar_99 = returns[returns <= var_99].mean()
64
+
65
+ # Skewness and Kurtosis
66
+ skewness = returns.skew()
67
+ kurtosis = returns.kurtosis()
68
+
69
+ return {
70
+ 'var_95': var_95,
71
+ 'var_99': var_99,
72
+ 'cvar_95': cvar_95,
73
+ 'cvar_99': cvar_99,
74
+ 'skewness': skewness,
75
+ 'kurtosis': kurtosis
76
+ }
77
+
78
+ def calculate_portfolio_metrics(self, portfolio_values: pd.Series) -> Dict[str, float]:
79
+ """Calculate portfolio-level metrics."""
80
+ if len(portfolio_values) < 2:
81
+ return {}
82
+
83
+ returns = portfolio_values.pct_change().dropna()
84
+
85
+ # Rolling metrics
86
+ rolling_returns = returns.rolling(window=252) # Annual window
87
+
88
+ return {
89
+ 'total_return': (portfolio_values.iloc[-1] / portfolio_values.iloc[0]) - 1,
90
+ 'annualized_return': (1 + returns.mean()) ** 252 - 1,
91
+ 'volatility': returns.std() * np.sqrt(252),
92
+ 'sharpe_ratio': returns.mean() / returns.std() * np.sqrt(252) if returns.std() > 0 else 0,
93
+ 'max_drawdown': self._calculate_max_drawdown(portfolio_values),
94
+ 'calmar_ratio': self._calculate_calmar_ratio(returns)
95
+ }
96
+
97
+ def _calculate_max_drawdown(self, values: pd.Series) -> float:
98
+ """Calculate maximum drawdown."""
99
+ peak = values.expanding().max()
100
+ drawdown = (values - peak) / peak
101
+ return drawdown.min()
102
+
103
+ def _calculate_calmar_ratio(self, returns: pd.Series) -> float:
104
+ """Calculate Calmar ratio."""
105
+ annual_return = (1 + returns.mean()) ** 252 - 1
106
+ max_dd = abs(self._calculate_max_drawdown((1 + returns).cumprod()))
107
+
108
+ if max_dd == 0:
109
+ return float('inf') if annual_return > 0 else 0.0
110
+
111
+ return annual_return / max_dd
112
+
113
+
@@ -0,0 +1,81 @@
1
+ """
2
+ Performance analysis for backtests.
3
+ """
4
+
5
+ import pandas as pd
6
+ import numpy as np
7
+ from typing import Dict, List, Any
8
+ from ..core.base import BaseComponent
9
+
10
+
11
+ class PerformanceAnalyzer(BaseComponent):
12
+ """Analyze backtest performance."""
13
+
14
+ def initialize(self) -> bool:
15
+ """Initialize performance analyzer."""
16
+ self.logger.info("Initializing performance analyzer")
17
+ return True
18
+
19
+ def calculate_returns(self, prices: pd.Series) -> pd.Series:
20
+ """Calculate returns from price series."""
21
+ return prices.pct_change().dropna()
22
+
23
+ def calculate_sharpe_ratio(self, returns: pd.Series, risk_free_rate: float = 0.02) -> float:
24
+ """Calculate Sharpe ratio."""
25
+ if len(returns) == 0 or returns.std() == 0:
26
+ return 0.0
27
+
28
+ excess_returns = returns - risk_free_rate / 252 # Daily risk-free rate
29
+ return excess_returns.mean() / returns.std() * np.sqrt(252)
30
+
31
+ def calculate_max_drawdown(self, returns: pd.Series) -> float:
32
+ """Calculate maximum drawdown."""
33
+ cumulative = (1 + returns).cumprod()
34
+ running_max = cumulative.expanding().max()
35
+ drawdown = (cumulative - running_max) / running_max
36
+ return drawdown.min()
37
+
38
+ def calculate_volatility(self, returns: pd.Series) -> float:
39
+ """Calculate annualized volatility."""
40
+ return returns.std() * np.sqrt(252)
41
+
42
+ def analyze_performance(self, returns: pd.Series, benchmark_returns: pd.Series = None) -> Dict[str, float]:
43
+ """Comprehensive performance analysis."""
44
+ analysis = {
45
+ 'total_return': (1 + returns).prod() - 1,
46
+ 'annualized_return': (1 + returns).prod() ** (252 / len(returns)) - 1,
47
+ 'volatility': self.calculate_volatility(returns),
48
+ 'sharpe_ratio': self.calculate_sharpe_ratio(returns),
49
+ 'max_drawdown': self.calculate_max_drawdown(returns),
50
+ 'win_rate': (returns > 0).mean(),
51
+ 'profit_factor': self._calculate_profit_factor(returns)
52
+ }
53
+
54
+ if benchmark_returns is not None:
55
+ analysis['alpha'] = self._calculate_alpha(returns, benchmark_returns)
56
+ analysis['beta'] = self._calculate_beta(returns, benchmark_returns)
57
+
58
+ return analysis
59
+
60
+ def _calculate_profit_factor(self, returns: pd.Series) -> float:
61
+ """Calculate profit factor."""
62
+ positive_returns = returns[returns > 0].sum()
63
+ negative_returns = abs(returns[returns < 0].sum())
64
+
65
+ if negative_returns == 0:
66
+ return float('inf') if positive_returns > 0 else 0.0
67
+
68
+ return positive_returns / negative_returns
69
+
70
+ def _calculate_alpha(self, returns: pd.Series, benchmark_returns: pd.Series) -> float:
71
+ """Calculate alpha."""
72
+ # Simplified calculation
73
+ return returns.mean() - benchmark_returns.mean()
74
+
75
+ def _calculate_beta(self, returns: pd.Series, benchmark_returns: pd.Series) -> float:
76
+ """Calculate beta."""
77
+ if benchmark_returns.var() == 0:
78
+ return 0.0
79
+ return returns.cov(benchmark_returns) / benchmark_returns.var()
80
+
81
+
@@ -0,0 +1,91 @@
1
+ """
2
+ Backtest report generation.
3
+ """
4
+
5
+ import pandas as pd
6
+ from typing import Dict, Any, Optional
7
+ from ..core.base import BaseComponent
8
+
9
+
10
+ class BacktestReporter(BaseComponent):
11
+ """Generate backtest reports."""
12
+
13
+ def initialize(self) -> bool:
14
+ """Initialize backtest reporter."""
15
+ self.logger.info("Initializing backtest reporter")
16
+ return True
17
+
18
+ def generate_summary_report(self, results: Dict[str, Any]) -> str:
19
+ """Generate a summary report."""
20
+ report = f"""
21
+ === Backtest Summary Report ===
22
+
23
+ Initial Capital: ${results.get('initial_capital', 0):,.2f}
24
+ Final Value: ${results.get('final_value', 0):,.2f}
25
+ Total Return: {results.get('total_return', 0):.2%}
26
+
27
+ Trades:
28
+ - Total Trades: {len(results.get('trades', []))}
29
+ - Final Cash: ${results.get('final_cash', 0):,.2f}
30
+ - Final Positions: {results.get('final_positions', {})}
31
+
32
+ === End of Report ===
33
+ """
34
+ return report
35
+
36
+ def generate_detailed_report(self, results: Dict[str, Any], performance_metrics: Dict[str, float]) -> str:
37
+ """Generate detailed report with performance metrics."""
38
+ report = f"""
39
+ === Detailed Backtest Report ===
40
+
41
+ PORTFOLIO PERFORMANCE
42
+ ====================
43
+ Initial Capital: ${results.get('initial_capital', 0):,.2f}
44
+ Final Value: ${results.get('final_value', 0):,.2f}
45
+ Total Return: {results.get('total_return', 0):.2%}
46
+
47
+ PERFORMANCE METRICS
48
+ ==================
49
+ Annualized Return: {performance_metrics.get('annualized_return', 0):.2%}
50
+ Volatility: {performance_metrics.get('volatility', 0):.2%}
51
+ Sharpe Ratio: {performance_metrics.get('sharpe_ratio', 0):.2f}
52
+ Maximum Drawdown: {performance_metrics.get('max_drawdown', 0):.2%}
53
+ Calmar Ratio: {performance_metrics.get('calmar_ratio', 0):.2f}
54
+
55
+ TRADING METRICS
56
+ ===============
57
+ Total Trades: {len(results.get('trades', []))}
58
+ Final Cash: ${results.get('final_cash', 0):,.2f}
59
+ Final Positions: {results.get('final_positions', {})}
60
+
61
+ === End of Detailed Report ===
62
+ """
63
+ return report
64
+
65
+ def save_report(self, report: str, filename: str) -> bool:
66
+ """Save report to file."""
67
+ try:
68
+ with open(filename, 'w') as f:
69
+ f.write(report)
70
+ self.logger.info(f"Report saved to: {filename}")
71
+ return True
72
+ except Exception as e:
73
+ self.logger.error(f"Failed to save report: {str(e)}")
74
+ return False
75
+
76
+ def export_trades_to_csv(self, trades: list, filename: str) -> bool:
77
+ """Export trades to CSV file."""
78
+ try:
79
+ if trades:
80
+ trade_df = pd.DataFrame(trades)
81
+ trade_df.to_csv(filename, index=False)
82
+ self.logger.info(f"Trades exported to: {filename}")
83
+ return True
84
+ else:
85
+ self.logger.warning("No trades to export")
86
+ return False
87
+ except Exception as e:
88
+ self.logger.error(f"Failed to export trades: {str(e)}")
89
+ return False
90
+
91
+
@@ -0,0 +1,19 @@
1
+ """
2
+ Core functionality for DeltaFQ.
3
+ """
4
+
5
+ from .config import Config
6
+ from .logger import Logger
7
+ from .exceptions import DeltaFQError, DataError, TradingError
8
+ from .base import BaseComponent
9
+
10
+ __all__ = [
11
+ "Config",
12
+ "Logger",
13
+ "DeltaFQError",
14
+ "DataError",
15
+ "TradingError",
16
+ "BaseComponent"
17
+ ]
18
+
19
+
deltafq/core/base.py ADDED
@@ -0,0 +1,37 @@
1
+ """
2
+ Base classes for DeltaFQ components.
3
+ """
4
+
5
+ from abc import ABC, abstractmethod
6
+ from typing import Any, Dict
7
+ from .logger import Logger
8
+ from .config import Config
9
+
10
+
11
+ class BaseComponent(ABC):
12
+ """Base class for all DeltaFQ components."""
13
+
14
+ def __init__(self, name: str = None, config: Config = None):
15
+ """Initialize base component."""
16
+ self.name = name or self.__class__.__name__
17
+ self.config = config or Config()
18
+ self.logger = Logger(self.name)
19
+
20
+ @abstractmethod
21
+ def initialize(self) -> bool:
22
+ """Initialize the component."""
23
+ pass
24
+
25
+ def cleanup(self):
26
+ """Cleanup resources."""
27
+ pass
28
+
29
+ def get_info(self) -> Dict[str, Any]:
30
+ """Get component information."""
31
+ return {
32
+ "name": self.name,
33
+ "class": self.__class__.__name__,
34
+ "config": self.config.config
35
+ }
36
+
37
+
deltafq/core/config.py ADDED
@@ -0,0 +1,63 @@
1
+ """
2
+ Configuration management for DeltaFQ.
3
+ """
4
+
5
+ import os
6
+ from typing import Dict, Any
7
+ from pathlib import Path
8
+
9
+
10
+ class Config:
11
+ """Configuration manager for DeltaFQ."""
12
+
13
+ def __init__(self, config_file: str = None):
14
+ """Initialize configuration."""
15
+ self.config = self._load_default_config()
16
+ if config_file and os.path.exists(config_file):
17
+ self._load_config_file(config_file)
18
+
19
+ def _load_default_config(self) -> Dict[str, Any]:
20
+ """Load default configuration."""
21
+ return {
22
+ "data": {
23
+ "cache_dir": "./data_cache",
24
+ "default_source": "yahoo"
25
+ },
26
+ "trading": {
27
+ "initial_capital": 100000,
28
+ "commission": 0.001,
29
+ "slippage": 0.0005
30
+ },
31
+ "logging": {
32
+ "level": "INFO",
33
+ "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
34
+ }
35
+ }
36
+
37
+ def _load_config_file(self, config_file: str):
38
+ """Load configuration from file."""
39
+ # Placeholder for config file loading
40
+ pass
41
+
42
+ def get(self, key: str, default: Any = None) -> Any:
43
+ """Get configuration value."""
44
+ keys = key.split('.')
45
+ value = self.config
46
+ for k in keys:
47
+ if isinstance(value, dict) and k in value:
48
+ value = value[k]
49
+ else:
50
+ return default
51
+ return value
52
+
53
+ def set(self, key: str, value: Any):
54
+ """Set configuration value."""
55
+ keys = key.split('.')
56
+ config = self.config
57
+ for k in keys[:-1]:
58
+ if k not in config:
59
+ config[k] = {}
60
+ config = config[k]
61
+ config[keys[-1]] = value
62
+
63
+