Skip to content

Commit 456f5fc

Browse files
authored
added technicals and optimizations (#29)
* added technicals and optimizations * formatting * bbands normalize * updated git ignore
1 parent 6f928c8 commit 456f5fc

17 files changed

+87
-45
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
_trial_temp/
12
.idea
23
.DS_Store
34
*.pyc

src/algotrader/calc/calculations.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ class TechnicalCalculation(Enum):
1616
OBV = 'obv'
1717
VAR = 'var'
1818
VOSC = 'vosc'
19+
STOCH = 'stoch'
20+
FISHER = 'fisher'
21+
AROONOSC = 'aroonosc'
22+
BBANDS = 'bbands'

src/algotrader/calc/technicals.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def fisher(self, period: int) -> List[float]:
6464
return ti.fisher(self._highs, self._lows, period)
6565

6666
def aroonosc(self, period: int) -> List[float]:
67-
if len(self._highs) < period:
67+
if len(self._highs) <= period:
6868
return []
6969

7070
return ti.aroonosc(self._highs, self._lows, period)

src/algotrader/examples/pipeline-templates/backtest_history_buckets_backtester.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,17 @@
547547
"ema20",
548548
"correlation"
549549
],
550-
"return_field": "ctc1",
550+
"return_fields": [
551+
"ctc-1",
552+
"ctc-2",
553+
"ctc-3",
554+
"ctc-4",
555+
"ctc-5",
556+
"ctc-6",
557+
"ctc-7",
558+
"ctc-8",
559+
"ctc-9"
560+
],
551561
"min_event_count": 50,
552562
"min_avg_return": 0.2
553563
}

src/algotrader/examples/pipeline-templates/backtest_technicals_with_buckets_calculator.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,7 @@
11621162
"ZTS"
11631163
],
11641164
"bins_count": 10,
1165-
"output_file_path": "/Users/idanyael/personal-dev/algo-trader/src/algotrader/examples/pipeline-templates/bins.json"
1165+
"output_file_path": "/Users/idanyael/personal-dev/algo-trader/src/algotrader/examples/pipeline-templates/bins.json",
1166+
"outliers_removal_percentage": 0.05
11661167
}
11671168
}

src/algotrader/examples/pipeline-templates/loader_simple_returns_calculator.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,8 @@
515515
}
516516
},
517517
"processor": {
518-
"returnsCount": 5
518+
"returnsCount": 5,
519+
"fieldPrefix": "ctc"
519520
},
520521
"terminator": null
521522
}

src/algotrader/pipeline/builders/backtest.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def build_mongodb_history_buckets_backtester(bins_file_path: str) -> Pipeline:
4343
data_from_time = STATIC_NOW - timedelta(days=365 * 3)
4444
source = MongoDBSource(mongodb_storage, symbols, TimeSpan.Day, backtest_from_time, STATIC_NOW)
4545

46+
return_fields = [f'ctc-{i}' for i in range(1, 10)]
47+
4648
history_compare_strategy = HistoryBucketCompareStrategy(mongodb_storage,
4749
data_from_time,
4850
backtest_from_time,
@@ -51,7 +53,7 @@ def build_mongodb_history_buckets_backtester(bins_file_path: str) -> Pipeline:
5153
'rsi7', 'rsi14',
5254
'stddev5', 'ema5',
5355
'ema20', 'correlation'],
54-
return_field='ctc1', min_event_count=50,
56+
return_fields=return_fields, min_event_count=50,
5557
min_avg_return=0.2)
5658

5759
cache_processor = CandleCache()

src/algotrader/pipeline/builders/loaders.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def build_returns_calculator(days_back: int = DEFAULT_DAYS_BACK) -> Pipeline:
104104

105105
sink = StorageSinkProcessor(mongodb_storage)
106106
cache_processor = CandleCache(sink)
107-
processor = ReturnsCalculatorProcessor(5, cache_processor)
107+
processor = ReturnsCalculatorProcessor('ctc', 5, cache_processor)
108108

109109
return Pipeline(source, processor)
110110

src/algotrader/pipeline/pipeline.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import logging
22
from typing import Optional, Dict
33

4-
from rich.progress import Progress, TextColumn, BarColumn
5-
64
from algotrader.entities.serializable import Serializable, Deserializable
75
from algotrader.pipeline.processor import Processor
86
from algotrader.pipeline.shared_context import SharedContext
@@ -37,13 +35,10 @@ def deserialize(cls, data: Dict):
3735
def run(self, context: SharedContext) -> None:
3836
self.logger.info('Starting pipeline...')
3937

40-
with Progress(TextColumn('{task.completed} Candle(s) processed'), BarColumn()) as progress:
41-
processing_task = progress.add_task("Processing", total=None)
42-
43-
for candle in self.source.read():
44-
self.logger.debug('Processing candle: %s\r', candle.serialize())
45-
self.processor.process(context, candle)
46-
progress.update(processing_task, advance=1)
38+
for candle in self.source.read():
39+
self.logger.debug('Processing candle: %s\r', candle.serialize())
40+
self.processor.process(context, candle)
4741

4842
if self.terminator:
43+
self.logger.debug('initiating termination...')
4944
self.terminator.terminate(context)

src/algotrader/pipeline/processors/returns.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@ class Returns(GenericCandleAttachment[float]):
1919

2020

2121
class ReturnsCalculatorProcessor(Processor):
22-
def __init__(self, returns_count: int, next_processor: Optional[Processor] = None):
22+
def __init__(self, field_prefix: str, returns_count: int, next_processor: Optional[Processor] = None):
2323
super().__init__(next_processor)
24+
self.field_prefix = field_prefix
2425
self.returns_count = returns_count
2526

2627
def process(self, context: SharedContext, candle: Candle):
2728
cache_reader = CandleCache.context_reader(context)
2829
symbol_candles = cache_reader.get_symbol_candles(candle.symbol) or []
2930

30-
if len(symbol_candles) > self.returns_count:
31+
candle.attachments.add_attachement(RETURNS_ATTACHMENT_KEY, Returns())
32+
33+
if len(symbol_candles) >= self.returns_count:
3134
candle_returns = self._calc_returns(candle, symbol_candles)
3235
candle.attachments.add_attachement(RETURNS_ATTACHMENT_KEY, candle_returns)
3336

@@ -36,16 +39,17 @@ def process(self, context: SharedContext, candle: Candle):
3639

3740
def _calc_returns(self, current_candle: Candle, candles: List[Candle]) -> Returns:
3841
candle_returns = Returns()
39-
for i in range(1, self.returns_count):
40-
candle_returns.set(f'ctc{i}', (1 - current_candle.close / candles[-i].close) * 100)
42+
for i in range(1, self.returns_count + 1):
43+
candle_returns.set(f'{self.field_prefix}-{i}', (1 - current_candle.close / candles[-i].close) * 100)
4144

4245
return candle_returns
4346

4447
def serialize(self) -> Dict:
4548
return {
46-
'returnsCount': self.returns_count
49+
'returnsCount': self.returns_count,
50+
'fieldPrefix': self.field_prefix
4751
}
4852

4953
@classmethod
5054
def deserialize(cls, data: Dict) -> Optional[Processor]:
51-
return cls(data['returnsCount'], cls._deserialize_next_processor(data))
55+
return cls(data['fieldPrefix'], data['returnsCount'], cls._deserialize_next_processor(data))

0 commit comments

Comments
 (0)