refactor/code-style-standardization #1
151
CLAUDE.md
Normal file
151
CLAUDE.md
Normal file
@ -0,0 +1,151 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a Python-based algorithmic trading system for financial markets that implements technical indicator analysis, signal generation, decision making, and risk management. It integrates with Tinkoff Invest API for market data and trading.
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Environment Setup
|
||||
- Python 3.9-3.12 (managed via Poetry)
|
||||
- Install dependencies: `poetry install`
|
||||
- Activate virtual environment: `poetry shell`
|
||||
- Environment variables are in `.env` (contains Tinkoff API tokens)
|
||||
|
||||
### Docker Development
|
||||
- Build image: `docker build -f dockerfiles/Dockerfile -t market-trade .`
|
||||
- Main Dockerfile uses Poetry 1.7.1 and Python 3.11
|
||||
- Requires SSH mount for private tinkoff-grpc dependency
|
||||
|
||||
### Running Tests
|
||||
- Test files located in `market_trade/tests/`
|
||||
- Run test: `python market_trade/tests/test_decision.py`
|
||||
- Run specific test: `python market_trade/tests/test_dataloader.py`
|
||||
|
||||
### Data Tools
|
||||
Scripts in `tools/` directory for data collection:
|
||||
- `save_currencies_data.py` - Collect currency market data
|
||||
- `save_shares_data.py` - Collect stock market data
|
||||
- `get_shares_stats.py` - Generate trading statistics
|
||||
- Usage: `python tools/<script_name>.py [options]`
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Trading Pipeline (docs/trading-flow.md)
|
||||
|
||||
The system follows this data flow:
|
||||
1. **SELECT INSTRUMENT** - Choose trading instrument
|
||||
2. **GET_CANDLES(10000)** - Fetch historical candlestick data
|
||||
3. **RETRO TRAINING** - Backtest signals on historical data
|
||||
4. **STREAM PROCESSING**:
|
||||
- Receive real-time market messages
|
||||
- Accumulate data in sliding window
|
||||
- Update window with each new message
|
||||
- Generate trading signals
|
||||
|
||||
### Module Structure
|
||||
|
||||
#### `market_trade/core/` - Core Trading Logic
|
||||
|
||||
**Signal Processing Chain:**
|
||||
1. **Indicators** (`indicators.py`, `indicators_v2.py`) - Technical indicator calculation
|
||||
- Base class: `coreIndicator`
|
||||
- Bollinger Bands: `ind_BB`
|
||||
- All indicator classes (Ind_*.py): ADX, Alligator, DonchianChannel, Envelopes, Gator, Ishimoku, LRI, STD, Stochastic, bollingerBands
|
||||
|
||||
2. **Signals** (`signals.py`, `signals_v2.py`) - Signal generation from indicators
|
||||
- Base class: `coreSignalTrande` with three modes:
|
||||
- `online` - Real-time signal generation
|
||||
- `retro` - Expanding window backtesting
|
||||
- `retroFast` - Sliding window backtesting
|
||||
- Signal implementations: `signal_BB` (Bollinger Bands signal)
|
||||
- Aggregator: `signalAgrigator` manages multiple signal instances
|
||||
|
||||
3. **Decision Manager** (`decisionManager.py`, `decisionManager_v2.py`) - Trading decisions
|
||||
- Class: `decsionManager`
|
||||
- Combines signals from `signalAgrigator`
|
||||
- Uses `trandeVoter` for probability matrix generation
|
||||
- Methods:
|
||||
- `getSignalTest()` - Test signal generation
|
||||
- `generateMatrixProbability()` - Create probability matrices from backtest
|
||||
- `getOnlineAns()` - Real-time decision making
|
||||
|
||||
4. **Trade Voter** (`trandeVoter.py`) - Probability-based decision weighting
|
||||
- Generates probability matrices from historical signal performance
|
||||
- Weights multiple signals to produce final decision
|
||||
|
||||
5. **Risk Manager** (`riskManager.py`) - Position sizing and risk controls
|
||||
- Class: `riskManager`
|
||||
- Combines signal decisions with risk parameters
|
||||
|
||||
6. **Deal Manager** (`dealManager.py`) - Trade execution and management
|
||||
- Class: `DealManager`
|
||||
- Manages active positions and orders
|
||||
|
||||
**Helper Modules:**
|
||||
- `CoreTradeMath.py` - Mathematical operations for indicators (moving averages, STD)
|
||||
- `CoreDraw.py` - Visualization utilities for indicators and signals
|
||||
|
||||
#### `market_trade/data/` - Data Loading
|
||||
|
||||
- `dataloader.py` - Contains `DukaMTInterface` class
|
||||
- Converts Dukascopy format candlestick data to internal format
|
||||
- Separates bid/ask candlesticks from multi-indexed CSV
|
||||
- Handles both file paths and DataFrames
|
||||
|
||||
#### `market_trade/tests/` - Testing
|
||||
|
||||
- Test files demonstrate usage patterns:
|
||||
- `test_decision.py` - Shows complete decision manager workflow with retro training
|
||||
- `test_dataloader.py` - Data loading tests
|
||||
|
||||
### External Dependencies
|
||||
|
||||
- **tinkoff-grpc** - Private GitHub repo for Tinkoff Invest API integration
|
||||
- Located at: `git@github.com:strategy155/tinkoff_grpc.git`
|
||||
- Used in tools for market data collection
|
||||
- **Data Analysis**: pandas, numpy, scipy, matplotlib, plotly, mplfinance
|
||||
- **Web Scraping**: requests-html, beautifulsoup4, selenium
|
||||
- **Development**: JupyterLab (notebooks in `notebooks/`)
|
||||
|
||||
## Key Constants (market_trade/constants.py)
|
||||
|
||||
- `ROOT_PATH` - Project root directory
|
||||
- `CANDLESTICK_DATASETS_PATH` - Path to candlestick data: `data/candlesticks/`
|
||||
- `TEST_CANDLESTICKS_PATH` - Test dataset: `data/EURUSD_price_candlestick.csv`
|
||||
- `TINKOFF_TOKEN_STRING` - Production API token (from .env)
|
||||
- `SANDBOX_TOKEN_STRING` - Sandbox API token (from .env)
|
||||
- `TINKOFF_API_ADDRESS` - API endpoint: 'invest-public-api.tinkoff.ru:443'
|
||||
|
||||
## Data Formats
|
||||
|
||||
### Candlestick Data
|
||||
Expected DataFrame columns:
|
||||
- `date` - Timestamp
|
||||
- `open`, `high`, `low`, `close` - OHLC price data
|
||||
- For bid/ask data: Multi-indexed with ('bid'/'ask', 'open'/'high'/'low'/'close')
|
||||
|
||||
### Signal Configuration Dictionary
|
||||
```python
|
||||
{
|
||||
'signal_name': {
|
||||
'className': signal_class, # e.g., sig_BB
|
||||
'indParams': {...}, # Indicator parameters
|
||||
'signalParams': { # Signal parameters
|
||||
'source': 'close', # Source price column
|
||||
'target': 'close' # Target price column for analysis
|
||||
},
|
||||
'batchSize': 30 # Window size
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Development Notes
|
||||
|
||||
- Code contains Russian comments and variable names (e.g., "агрегатор", "индикаторы")
|
||||
- Version 2 modules (`*_v2.py`) represent newer implementations
|
||||
- The system uses sliding window approach for real-time signal generation
|
||||
- Backtesting generates probability matrices that weight signal reliability
|
||||
- Data symlink: `data/` -> `/var/data0/markettrade_data`
|
||||
0
docs/trading-flow.md
Normal file
0
docs/trading-flow.md
Normal file
@ -25,7 +25,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
init_notebook_mode()
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import plotly.express as px
|
||||
|
||||
|
||||
|
||||
137
market_trade/core/CoreTradeMath.py
Normal file
137
market_trade/core/CoreTradeMath.py
Normal file
@ -0,0 +1,137 @@
|
||||
|
||||
import pandas as pd
|
||||
import datetime
|
||||
import numpy as np
|
||||
import plotly as pl
|
||||
import plotly.graph_objs as go
|
||||
import matplotlib.pyplot as plt
|
||||
import math
|
||||
import scipy
|
||||
import random
|
||||
import statistics
|
||||
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class CoreMath:
|
||||
|
||||
def __init__(self, base_df, params=None):
|
||||
default_params = {
|
||||
'dataType':'ohcl',
|
||||
'action': None,
|
||||
'actionOptions':{}
|
||||
}
|
||||
self.base_df=base_df.reset_index(drop=True)
|
||||
self.params=params if params is not None else default_params
|
||||
|
|
||||
if self.params['dataType']=='ohcl':
|
||||
self.col=self.base_df[self.params['actionOptions']['valueType']]
|
||||
elif self.params['dataType']=='series':
|
||||
self.col=self.base_df
|
||||
self.ans=self.getAns()
|
||||
|
||||
|
||||
def getAns(self):
|
||||
ans=None
|
||||
|
||||
if self.params['action']=='findExt':
|
||||
ans = self.getExtremumValue()
|
||||
elif self.params['action']=='findMean':
|
||||
ans = self.getMeanValue()
|
||||
elif self.params['action']=='findSTD':
|
||||
ans=self.getSTD()
|
||||
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
def getExtremumValue(self):
|
||||
ans=None
|
||||
'''
|
||||
actionOptions:
|
||||
'extremumtype':
|
||||
'min'
|
||||
'max'
|
||||
'valueType':
|
||||
'open'
|
||||
'close'
|
||||
'high'
|
||||
'low'
|
||||
'''
|
||||
if self.params['actionOptions']['extremumtype']=='max':
|
||||
ans=max(self.col)
|
||||
|
||||
if self.params['actionOptions']['extremumtype']=='min':
|
||||
ans=min(self.col)
|
||||
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
def getMeanValue(self):
|
||||
'''
|
||||
actionOptions:
|
||||
'MeanType':
|
||||
'MA'
|
||||
'SMA'
|
||||
'EMA'
|
||||
'WMA'
|
||||
--'SMMA'
|
||||
'valueType':
|
||||
'open'
|
||||
'close'
|
||||
'high'
|
||||
'low'
|
||||
'window'
|
||||
'span'
|
||||
'weights'
|
||||
'''
|
||||
ans=None
|
||||
if self.params['actionOptions']['MeanType']=='MA':
|
||||
ans = self.col.mean()
|
||||
if self.params['actionOptions']['MeanType']=='SMA':
|
||||
ans=np.convolve(self.col, np.ones(self.params['actionOptions']['window']), 'valid') / self.params['actionOptions']['window']
|
||||
#ans=self.col.rolling(window=self.params['actionOptions']['window']).mean().to_list()
|
||||
|
||||
if self.params['actionOptions']['MeanType']=='EMA':
|
||||
ans=self.col.ewm(span=self.params['actionOptions']['span'], adjust=False).mean().to_list()
|
||||
if self.params['actionOptions']['MeanType']=='WMA':
|
||||
try:
|
||||
weights=self.params['actionOptions']['weights']
|
||||
except KeyError:
|
||||
weights=np.arange(1,self.params['actionOptions']['window']+1)
|
||||
ans=self.col.rolling(window=self.params['actionOptions']['window']).apply(lambda x: np.sum(weights*x) / weights.sum(), raw=False).to_list()
|
||||
|
||||
|
||||
|
||||
return(ans)
|
||||
|
||||
def getSTD(self):
|
||||
'''
|
||||
actionOptions:
|
||||
window
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
'''
|
||||
|
||||
ans=None
|
||||
|
||||
|
||||
try:
|
||||
window=self.params['actionOptions']['window']
|
||||
ans=np.asarray([])
|
||||
for i in range(len(self.col)-window+1):
|
||||
ans=np.append(ans,np.std(self.col[i:i+window], ddof=1))
|
||||
|
||||
except:
|
||||
#window = len(self.col)
|
||||
ans=np.std(self.col, ddof=1)
|
||||
|
||||
return ans
|
||||
|
||||
@ -25,7 +25,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
init_notebook_mode()
|
||||
|
||||
@ -82,7 +82,7 @@ class ADXI:
|
||||
'action':'findMean',
|
||||
'actionOptions':{'MeanType':'EMA','span':10}
|
||||
}
|
||||
ans=np.asarray(CoreTraidMath.CoreMath(ser,op).ans)
|
||||
ans=np.asarray(CoreTradeMath.CoreMath(ser,op).ans)
|
||||
|
strategy155
commented
Horrible naming. Horrible naming.
|
||||
#print(ans)
|
||||
#ans = np.asarray(ser.ewm(span=40,adjust=False).mean().to_list())
|
||||
#print(ans)
|
||||
|
||||
@ -24,7 +24,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
init_notebook_mode()
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ class Alligator:
|
||||
'valueType':self.options['valueType'],
|
||||
'window':self.options[keyAns]['window']}
|
||||
}
|
||||
ans=market_trade.core.CoreTraidMath.CoreMath(self.base_df,op).ans
|
||||
ans=market_trade.core.CoreTradeMath.CoreMath(self.base_df,op).ans
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
init_notebook_mode()
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
|
||||
|
||||
@ -62,9 +62,9 @@ class IDC:
|
||||
}
|
||||
|
||||
for i in range(self.options['window'],len(self.base_df)-self.options['shift']+1):
|
||||
ans['MaxExt'].append(CoreTraidMath.CoreMath(self.base_df[i-self.options['window']:i],opMax).ans)
|
||||
ans['MaxExt'].append(CoreTradeMath.CoreMath(self.base_df[i-self.options['window']:i],opMax).ans)
|
||||
|
strategy155
commented
All the operations like this should be decopupled, the variabels inside should be named properly, the keys in the dicts should be explicit and moved to constants. Along all places. All the operations like this should be decopupled, the variabels inside should be named properly, the keys in the dicts should be explicit and moved to constants. Along all places.
|
||||
ans['x'].append(self.base_df['date'][i-1+self.options['shift']])
|
||||
ans['MinExt'].append(CoreTraidMath.CoreMath(self.base_df[i-self.options['window']:i],opMin).ans)
|
||||
ans['MinExt'].append(CoreTradeMath.CoreMath(self.base_df[i-self.options['window']:i],opMin).ans)
|
||||
return ans
|
||||
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
init_notebook_mode()
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
|
||||
class Envelopes:
|
||||
@ -64,7 +64,7 @@ class Envelopes:
|
||||
}
|
||||
if dictResp['MeanType']=='SMA':
|
||||
|
||||
y=market_trade.core.CoreTraidMath.CoreMath(self.base_df,op).ans
|
||||
y=market_trade.core.CoreTradeMath.CoreMath(self.base_df,op).ans
|
||||
ans['MainEnv']=y[:len(y)-self.options['shift']]
|
||||
ans['PlusEnv']=ans['MainEnv']*(1+self.options['kProc']/100)
|
||||
ans['MinusEnv']=ans['MainEnv']*(1-self.options['kProc']/100)
|
||||
|
||||
@ -24,7 +24,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
init_notebook_mode()
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
import market_trade.core.Ind_Alligator
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
import market_trade.core.CoreDraw
|
||||
init_notebook_mode()
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import plotly.express as px
|
||||
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
init_notebook_mode()
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
init_notebook_mode()
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
|
||||
class ISTD:
|
||||
@ -53,7 +53,7 @@ class ISTD:
|
||||
'actionOptions':{'valueType':self.options['valueType']}
|
||||
}
|
||||
x=self.base_df['date'].to_list()
|
||||
y= CoreTraidMath.CoreMath(self.base_df,op).ans
|
||||
y= CoreTradeMath.CoreMath(self.base_df,op).ans
|
||||
|
strategy155
commented
Quite a bad naming here. Quite a bad naming here.
|
||||
ans={'y':y,'x':x}
|
||||
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
init_notebook_mode()
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
|
||||
class Stochastic:
|
||||
@ -69,7 +69,7 @@ class Stochastic:
|
||||
'action':'findMean',
|
||||
'actionOptions':{'MeanType':'SMA','window':self.options['windowSMA']}
|
||||
}
|
||||
ans=np.asarray(market_trade.core.CoreTraidMath.CoreMath(ser,op).ans)
|
||||
ans=np.asarray(market_trade.core.CoreTradeMath.CoreMath(ser,op).ans)
|
||||
return ans
|
||||
#return np.convolve(col, np.ones(self.options['windowSMA']), 'valid') /self.options['windowSMA']
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ from plotly.offline import init_notebook_mode, iplot
|
||||
from plotly.subplots import make_subplots
|
||||
init_notebook_mode()
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
|
||||
|
||||
@ -50,12 +50,12 @@ class BB:
|
||||
'window':self.options['window']
|
||||
}
|
||||
}
|
||||
ans['BB']=market_trade.core.CoreTraidMath.CoreMath(self.base_df,opMA).ans
|
||||
ans['BB']=market_trade.core.CoreTradeMath.CoreMath(self.base_df,opMA).ans
|
||||
opSTD={'dataType':'ohcl',
|
||||
'action':'findSTD',
|
||||
'actionOptions':{'valueType':self.options['valueType'],'window':self.options['window']}
|
||||
}
|
||||
ans['STD']=market_trade.core.CoreTraidMath.CoreMath(self.base_df,opSTD).ans
|
||||
ans['STD']=market_trade.core.CoreTradeMath.CoreMath(self.base_df,opSTD).ans
|
||||
ans['pSTD']=ans['BB']+ans['STD']*self.options['kDev']
|
||||
ans['mSTD']=ans['BB']-ans['STD']*self.options['kDev']
|
||||
ans['x']=np.array(self.base_df['date'][self.options['window']-1:].to_list())
|
||||
|
||||
@ -2,7 +2,7 @@ import pandas as pd
|
||||
import datetime
|
||||
import numpy as np
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
|
||||
class coreIndicator():
|
||||
@ -99,12 +99,12 @@ class ind_BB(coreIndicator):
|
||||
'window':self.options['window']
|
||||
}
|
||||
}
|
||||
ans['BB']=market_trade.core.CoreTraidMath.CoreMath(self.data,opMA).ans
|
||||
ans['BB']=market_trade.core.CoreTradeMath.CoreMath(self.data,opMA).ans
|
||||
opSTD={'dataType':'ohcl',
|
||||
'action':'findSTD',
|
||||
'actionOptions':{'valueType':self.options['valueType'],'window':self.options['window']}
|
||||
}
|
||||
ans['STD']=market_trade.core.CoreTraidMath.CoreMath(self.data,opSTD).ans
|
||||
ans['STD']=market_trade.core.CoreTradeMath.CoreMath(self.data,opSTD).ans
|
||||
ans['pSTD']=ans['BB']+ans['STD']*self.options['kDev']
|
||||
ans['mSTD']=ans['BB']-ans['STD']*self.options['kDev']
|
||||
ans['x']=np.array(self.data['date'][self.options['window']-1:].to_list())
|
||||
|
||||
@ -2,88 +2,158 @@ import pandas as pd
|
||||
import datetime
|
||||
import numpy as np
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
|
||||
class coreIndicator():
|
||||
|
||||
def __init__(self,options: dict, dataType: str = None, predictType: str = None, name: str = None):
|
||||
|
||||
class CoreIndicator():
|
||||
"""Base class for technical indicators.
|
||||
|
||||
This class provides the foundation for implementing various technical
|
||||
indicators used in trading signal generation.
|
||||
"""
|
||||
|
||||
def __init__(self, options: dict, data_type: str = None, predict_type: str = None, name: str = None):
|
||||
"""Initialize CoreIndicator with configuration options.
|
||||
|
||||
Args:
|
||||
options: Dictionary containing indicator-specific parameters.
|
||||
data_type: Type of data to process (e.g., 'ohlc'). Defaults to None.
|
||||
predict_type: Type of prediction to make (e.g., 'trend'). Defaults to None.
|
||||
name: Optional identifier. Defaults to None.
|
||||
"""
|
||||
self.options = options
|
||||
self.dataType = dataType #ochl
|
||||
self.predictType = predictType #trend
|
||||
|
||||
|
||||
def getAns(self, data: pd.DataFrame() ):
|
||||
self.data_type = data_type # ohlc
|
||||
self.predict_type = predict_type # trend
|
||||
|
||||
def get_answer(self, data: pd.DataFrame):
|
||||
"""Get indicator answer from data.
|
||||
|
||||
Args:
|
||||
data: DataFrame containing market data.
|
||||
|
||||
Returns:
|
||||
Calculated indicator values or "ERROR" if not implemented.
|
||||
"""
|
||||
return "ERROR"
|
||||
|
strategy155
commented
not normal, should be put to constant, or even better this system should be revound. not normal, should be put to constant, or even better this system should be revound.
|
||||
|
||||
class indicatorsAgrigator:
|
||||
"""
|
||||
indicators = {
|
||||
'ind_BB':{
|
||||
'className':ind_BB,
|
||||
'params':{'MeanType':'SMA','window':15,'valueType':'close','kDev':2.5}
|
||||
}
|
||||
}
|
||||
dataDic={
|
||||
'ind_BB':df_candle[:1000]
|
||||
}
|
||||
|
||||
|
||||
"""
|
||||
|
||||
def __init__ (self,indDict={}):
|
||||
self.indDict = indDict
|
||||
self.indInst = {}
|
||||
self.ans={}
|
||||
self.createIndicatorsInstance()
|
||||
|
||||
def createIndicatorsInstance(self):
|
||||
for i in self.indDict.keys():
|
||||
self.indInst[i]=self.indDict[i]['className'](self.indDict[i]['params'])
|
||||
|
||||
def getAns(self,dataDict={}):
|
||||
ans={}
|
||||
for i in dataDict.keys():
|
||||
ans[i] = self.indInst[i].getAns(dataDict[i])
|
||||
return ans
|
||||
|
||||
class ind_BB(coreIndicator):
|
||||
"""
|
||||
options
|
||||
MeanType -> SMA
|
||||
window -> int
|
||||
valueType -> str: low, high, open, close
|
||||
kDev -> float
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,options: dict,name = None):
|
||||
super().__init__(
|
||||
options = options,
|
||||
dataType = 'ochl',
|
||||
predictType = 'trend',
|
||||
name = name
|
||||
)
|
||||
|
||||
def getAns(self, data: pd.DataFrame()):
|
||||
data=data.reset_index(drop=True)
|
||||
ans={}
|
||||
opMA={'dataType':'ohcl',
|
||||
'action':'findMean',
|
||||
'actionOptions':{
|
||||
'MeanType':self.options['MeanType'],
|
||||
'valueType':self.options['valueType'],
|
||||
'window':self.options['window']
|
||||
|
||||
|
||||
class IndicatorsAggregator:
|
||||
|
strategy155
commented
Probably you also need to comment on the calsss tacttrbute,s per rgoogle codestyle no? Probably you also need to comment on the calsss tacttrbute,s per rgoogle codestyle no?
|
||||
"""Aggregates and manages multiple indicator instances.
|
||||
|
||||
Example usage:
|
||||
indicators = {
|
||||
'ind_BB': {
|
||||
'className': ind_BB,
|
||||
'params': {'MeanType': 'SMA', 'window': 15, 'valueType': 'close', 'kDev': 2.5}
|
||||
}
|
||||
}
|
||||
ans['BB']=market_trade.core.CoreTraidMath.CoreMath(data,opMA).ans
|
||||
opSTD={'dataType':'ohcl',
|
||||
'action':'findSTD',
|
||||
'actionOptions':{'valueType':self.options['valueType'],'window':self.options['window']}
|
||||
data_dict = {
|
||||
'ind_BB': df_candle[:1000]
|
||||
}
|
||||
ans['STD']=market_trade.core.CoreTraidMath.CoreMath(data,opSTD).ans
|
||||
ans['pSTD']=ans['BB']+ans['STD']*self.options['kDev']
|
||||
ans['mSTD']=ans['BB']-ans['STD']*self.options['kDev']
|
||||
ans['x']=np.array(data['date'][self.options['window']-1:].to_list())
|
||||
self.ans= ans
|
||||
aggregator = IndicatorsAggregator(indicators)
|
||||
results = aggregator.get_answer(data_dict)
|
||||
"""
|
||||
|
||||
def __init__(self, ind_dict=None):
|
||||
"""Initialize aggregator with indicator dictionary.
|
||||
|
||||
Args:
|
||||
ind_dict: Dictionary mapping indicator names to configurations.
|
||||
Defaults to empty dict if not provided.
|
||||
"""
|
||||
self.ind_dict = ind_dict if ind_dict is not None else {}
|
||||
|
strategy155
commented
whait is this. whait is this.
|
||||
self.ind_instances = {}
|
||||
self.ans = {}
|
||||
self.create_indicators_instance()
|
||||
|
||||
def create_indicators_instance(self):
|
||||
"""Create instances of all configured indicators."""
|
||||
for i in self.ind_dict.keys():
|
||||
self.ind_instances[i] = self.ind_dict[i]['className'](self.ind_dict[i]['params'])
|
||||
|
||||
def get_answer(self, data_dict=None):
|
||||
"""Calculate answers from all indicators.
|
||||
|
||||
Args:
|
||||
data_dict: Dictionary mapping indicator names to their data.
|
||||
Defaults to empty dict.
|
||||
|
||||
Returns:
|
||||
Dictionary of indicator results.
|
||||
"""
|
||||
if data_dict is None:
|
||||
data_dict = {}
|
||||
ans = {}
|
||||
for i in data_dict.keys():
|
||||
ans[i] = self.ind_instances[i].get_answer(data_dict[i])
|
||||
return ans
|
||||
|
strategy155
commented
all about it is horrible. all about it is horrible.
|
||||
|
||||
|
||||
class ind_BB(CoreIndicator):
|
||||
|
strategy155
commented
NAMING! NAMING!
|
||||
"""Bollinger Bands indicator implementation.
|
||||
|
||||
Calculates Bollinger Bands using moving average and standard deviation.
|
||||
|
||||
Required options:
|
||||
MeanType: Type of moving average (e.g., 'SMA')
|
||||
window: Period for calculations (int)
|
||||
valueType: Price type to use ('low', 'high', 'open', 'close')
|
||||
kDev: Standard deviation multiplier (float)
|
||||
"""
|
||||
|
||||
def __init__(self, options: dict, name=None):
|
||||
"""Initialize Bollinger Bands indicator.
|
||||
|
||||
Args:
|
||||
options: Configuration parameters dictionary.
|
||||
name: Optional identifier.
|
||||
"""
|
||||
super().__init__(
|
||||
options=options,
|
||||
data_type='ohlc',
|
||||
predict_type='trend',
|
||||
name=name
|
||||
)
|
||||
|
strategy155
commented
some problems I see here as welll. some problems I see here as welll.
|
||||
|
||||
def get_answer(self, data: pd.DataFrame):
|
||||
"""Calculate Bollinger Bands values.
|
||||
|
||||
Args:
|
||||
data: DataFrame with OHLC price data.
|
||||
|
||||
Returns:
|
||||
Dictionary containing:
|
||||
- BB: Middle band (moving average)
|
||||
- STD: Standard deviation
|
||||
- pSTD: Upper band (BB + kDev * STD)
|
||||
- mSTD: Lower band (BB - kDev * STD)
|
||||
- x: Date array
|
||||
"""
|
||||
data = data.reset_index(drop=True)
|
||||
ans = {}
|
||||
|
||||
op_ma = {
|
||||
'dataType': 'ohcl',
|
||||
'action': 'findMean',
|
||||
'actionOptions': {
|
||||
'MeanType': self.options['MeanType'],
|
||||
'valueType': self.options['valueType'],
|
||||
'window': self.options['window']
|
||||
}
|
||||
}
|
||||
ans['BB'] = market_trade.core.CoreTradeMath.CoreMath(data, op_ma).ans
|
||||
|
||||
op_std = {
|
||||
'dataType': 'ohcl',
|
||||
'action': 'findSTD',
|
||||
'actionOptions': {
|
||||
'valueType': self.options['valueType'],
|
||||
'window': self.options['window']
|
||||
}
|
||||
}
|
||||
ans['STD'] = market_trade.core.CoreTradeMath.CoreMath(data, op_std).ans
|
||||
ans['pSTD'] = ans['BB'] + ans['STD'] * self.options['kDev']
|
||||
ans['mSTD'] = ans['BB'] - ans['STD'] * self.options['kDev']
|
||||
ans['x'] = np.array(data['date'][self.options['window']-1:].to_list())
|
||||
self.ans = ans
|
||||
|
strategy155
commented
it is better, but please use normal intermediate variables operations, and the constants as keys. OR maybe to pydantic dataclasses we go? it is better, but please use normal intermediate variables operations, and the constants as keys. OR maybe to pydantic dataclasses we go?
|
||||
return ans
|
||||
|
||||
@ -2,7 +2,7 @@ import pandas as pd
|
||||
import datetime
|
||||
import numpy as np
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
import market_trade.core.CoreTradeMath
|
||||
import market_trade.core.CoreDraw
|
||||
from tqdm import tqdm
|
||||
|
||||
|
||||
@ -2,111 +2,172 @@ import pandas as pd
|
||||
import datetime
|
||||
import numpy as np
|
||||
|
||||
import market_trade.core.CoreTraidMath
|
||||
#import market_trade.core.CoreDraw
|
||||
import market_trade.core.CoreTradeMath
|
||||
from tqdm import tqdm
|
||||
|
||||
from market_trade.core.indicators_v2 import *
|
||||
from market_trade.core.indicators_v2 import IndicatorsAggregator, ind_BB
|
||||
|
||||
|
||||
class CoreSignalTrade:
|
||||
"""Base class for trading signals.
|
||||
|
||||
class coreSignalTrande:
|
||||
|
||||
def __init__(self, name: str, req: dict, dataType: str):
|
||||
Provides foundation for generating trading signals based on technical indicators.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, req: dict, data_type: str):
|
||||
"""Initialize signal generator.
|
||||
|
||||
Args:
|
||||
name: Signal identifier.
|
||||
req: Configuration dictionary containing params and indicators.
|
||||
data_type: Type of data to process (e.g., 'ohlc').
|
||||
"""
|
||||
self.name = name
|
||||
self.agrigateInds = self.createIndicatorsInstance(req)
|
||||
self.aggregate_indicators = self.create_indicators_instance(req)
|
||||
self.params = req['params']
|
||||
self.dataType = dataType
|
||||
|
||||
|
||||
def createIndicatorsInstance(self,req: dict) -> dict:
|
||||
return indicatorsAgrigator(req['indicators'])
|
||||
|
||||
def getIndAns(self, dataDict: dict) -> dict:
|
||||
return self.agrigateInds.getAns(dataDict)
|
||||
|
||||
def getAns(self, data: pd.DataFrame(), indDataDict: dict) -> dict:
|
||||
return self.getSigAns(data, self.getIndAns(indDataDict))
|
||||
|
||||
|
||||
|
||||
class sig_BB(coreSignalTrande):
|
||||
"""
|
||||
ind keys:
|
||||
ind_BB
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, req:dict):
|
||||
super().__init__(name, req, 'ochl')
|
||||
|
||||
def getSigAns(self, data: pd.DataFrame(), indAnsDict: dict) -> dict:
|
||||
self.data_type = data_type
|
||||
|
||||
lastValue = data[self.params['source']].to_list()[-1]
|
||||
if lastValue>indAnsDict['ind_BB']['pSTD'][-1]:
|
||||
ans='down'
|
||||
elif lastValue<indAnsDict['ind_BB']['mSTD'][-1]:
|
||||
ans='up'
|
||||
else:
|
||||
ans='none'
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
class signalsAgrigator:
|
||||
|
||||
def create_indicators_instance(self, req: dict) -> IndicatorsAggregator:
|
||||
"""Create indicators aggregator from configuration.
|
||||
|
||||
Args:
|
||||
req: Request dictionary containing indicators configuration.
|
||||
|
||||
Returns:
|
||||
IndicatorsAggregator instance.
|
||||
"""
|
||||
return IndicatorsAggregator(req['indicators'])
|
||||
|
strategy155
commented
is it a goodpattersn thoug'h, maybe we can formalise the dispatching scheme better? is it a goodpattersn thoug'h, maybe we can formalise the dispatching scheme better?
|
||||
|
||||
def get_indicator_answer(self, data_dict: dict) -> dict:
|
||||
"""Get answers from all indicators.
|
||||
|
||||
Args:
|
||||
data_dict: Dictionary mapping indicator names to data.
|
||||
|
||||
Returns:
|
||||
Dictionary of indicator results.
|
||||
"""
|
||||
return self.aggregate_indicators.get_answer(data_dict)
|
||||
|
||||
def get_answer(self, data: pd.DataFrame, ind_data_dict: dict) -> dict:
|
||||
"""Get signal answer from data and indicator results.
|
||||
|
||||
Args:
|
||||
data: Market data DataFrame.
|
||||
ind_data_dict: Dictionary of indicator data.
|
||||
|
||||
Returns:
|
||||
Signal answer (direction).
|
||||
"""
|
||||
return self.get_signal_answer(data, self.get_indicator_answer(ind_data_dict))
|
||||
|
||||
|
||||
class sig_BB(CoreSignalTrade):
|
||||
"""Bollinger Bands signal generator.
|
||||
|
||||
Generates trading signals based on Bollinger Bands indicator:
|
||||
- 'up' when price is below lower band
|
||||
- 'down' when price is above upper band
|
||||
- 'none' when price is within bands
|
||||
|
strategy155
commented
maybe more enums for things like this one? maybe more enums for things like this one?
|
||||
|
||||
Required indicator keys:
|
||||
ind_BB: Bollinger Bands indicator
|
||||
"""
|
||||
sigAgrReq = {
|
||||
'sig_BB':{
|
||||
'className':sig_BB,
|
||||
'params':{'source':'close','target':'close'},
|
||||
'indicators':{
|
||||
'ind_BB':{
|
||||
'className':ind_BB,
|
||||
'params':{'MeanType':'SMA','window':15,'valueType':'close','kDev':2.5}
|
||||
}
|
||||
}
|
||||
},
|
||||
'sig_BB_2':{
|
||||
'className':sig_BB,
|
||||
'params':{'source':'close','target':'close'},
|
||||
'indicators':{
|
||||
'ind_BB':{
|
||||
'className':ind_BB,
|
||||
'params':{'MeanType':'SMA','window':30,'valueType':'close','kDev':2}
|
||||
}
|
||||
|
||||
def __init__(self, name: str, req: dict):
|
||||
"""Initialize Bollinger Bands signal.
|
||||
|
||||
Args:
|
||||
name: Signal identifier.
|
||||
req: Configuration dictionary.
|
||||
"""
|
||||
super().__init__(name, req, 'ohlc')
|
||||
|
||||
def get_signal_answer(self, data: pd.DataFrame, ind_ans_dict: dict) -> str:
|
||||
"""Calculate signal from Bollinger Bands.
|
||||
|
||||
Args:
|
||||
data: Market data DataFrame.
|
||||
ind_ans_dict: Dictionary containing indicator results.
|
||||
|
||||
Returns:
|
||||
Signal direction: 'up', 'down', or 'none'.
|
||||
"""
|
||||
last_value = data[self.params['source']].to_list()[-1]
|
||||
if last_value > ind_ans_dict['ind_BB']['pSTD'][-1]:
|
||||
ans = 'down'
|
||||
elif last_value < ind_ans_dict['ind_BB']['mSTD'][-1]:
|
||||
ans = 'up'
|
||||
else:
|
||||
ans = 'none'
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
class SignalsAggregator:
|
||||
"""Aggregates and manages multiple signal generators.
|
||||
|
||||
Example usage:
|
||||
sig_config = {
|
||||
'sig_BB': {
|
||||
'className': sig_BB,
|
||||
'params': {'source': 'close', 'target': 'close'},
|
||||
'indicators': {
|
||||
'ind_BB': {
|
||||
'className': ind_BB,
|
||||
'params': {'MeanType': 'SMA', 'window': 15, 'valueType': 'close', 'kDev': 2.5}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sigAgrData = {
|
||||
'sig_BB':{
|
||||
'signalData': df_candle[990:1000],
|
||||
'indicatorData' :{'ind_BB': df_candle[:1000]}
|
||||
},
|
||||
'sig_BB_2':{
|
||||
'signalData': df_candle[990:1000],
|
||||
'indicatorData' :{'ind_BB': df_candle[:1000]}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sig_data = {
|
||||
'sig_BB': {
|
||||
'signalData': df_candle[990:1000],
|
||||
'indicatorData': {'ind_BB': df_candle[:1000]}
|
||||
}
|
||||
}
|
||||
|
||||
aggregator = SignalsAggregator(sig_config)
|
||||
results = aggregator.get_answer(sig_data)
|
||||
"""
|
||||
|
||||
def __init__ (self,req:dict):
|
||||
self.signals = self.createSignalsInstance(req)
|
||||
|
||||
def createSignalsInstance(self, siganlsDict: dict) -> dict:
|
||||
|
||||
def __init__(self, req: dict):
|
||||
"""Initialize signals aggregator.
|
||||
|
||||
Args:
|
||||
req: Dictionary mapping signal names to configurations.
|
||||
"""
|
||||
self.signals = self.create_signals_instance(req)
|
||||
|
||||
def create_signals_instance(self, signals_dict: dict) -> dict:
|
||||
"""Create instances of all configured signals.
|
||||
|
||||
Args:
|
||||
signals_dict: Dictionary of signal configurations.
|
||||
|
||||
Returns:
|
||||
Dictionary of signal instances.
|
||||
"""
|
||||
ans = {}
|
||||
for i in siganlsDict.keys():
|
||||
ans[i]=siganlsDict[i]['className'](name = i, req = siganlsDict[i])
|
||||
for i in signals_dict.keys():
|
||||
ans[i] = signals_dict[i]['className'](name=i, req=signals_dict[i])
|
||||
|
strategy155
commented
bloody hell bloody hell
|
||||
return ans
|
||||
|
||||
def getAns(self, dataDict: dict) -> dict:
|
||||
|
||||
def get_answer(self, data_dict: dict) -> dict:
|
||||
"""Calculate answers from all signals.
|
||||
|
||||
Args:
|
||||
data_dict: Dictionary mapping signal names to their data.
|
||||
Each entry should contain 'signalData' and 'indicatorData'.
|
||||
|
||||
Returns:
|
||||
Dictionary of signal results.
|
||||
"""
|
||||
ans = {}
|
||||
for i in dataDict.keys():
|
||||
ans[i] = self.signals[i].getAns(data = dataDict[i]['signalData'],
|
||||
indDataDict = dataDict[i]['indicatorData'])
|
||||
return ans
|
||||
for i in data_dict.keys():
|
||||
ans[i] = self.signals[i].get_answer(
|
||||
data=data_dict[i]['signalData'],
|
||||
ind_data_dict=data_dict[i]['indicatorData']
|
||||
)
|
||||
return ans
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user
bad practice