Skip to content

Commit 61905f8

Browse files
committed
add indicator comparison functionality
1 parent 608f4f9 commit 61905f8

File tree

9 files changed

+345
-126
lines changed

9 files changed

+345
-126
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
## Overview
1111

12-
Current Version: **0.1.0**
12+
Current Version: **0.1.1**
1313

1414
A trading robot written in Python that can run automated strategies using a technical analysis.
1515
The robot is designed to mimic a few common scenarios:

pyrobot/indicators.py

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ def __init__(self, price_data_frame: StockFrame) -> None:
4646
self._current_indicators = {}
4747
self._indicator_signals = {}
4848
self._frame = self._stock_frame.frame
49+
50+
self._indicators_comp_key = []
51+
self._indicators_key = []
4952

5053
if self.is_multi_index:
5154
True
@@ -66,11 +69,10 @@ def get_indicator_signal(self, indicator: Optional[str]= None) -> Dict:
6669
return self._indicator_signals[indicator]
6770
else:
6871
return self._indicator_signals
69-
7072

7173
def set_indicator_signal(self, indicator: str, buy: float, sell: float, condition_buy: Any, condition_sell: Any,
72-
buy_max: float = None, sell_max: float = None, condition_buy_max: Any = None, condition_sell_max: Any = None) -> None:
73-
"""Return the raw Pandas Dataframe Object.
74+
buy_max: float = None, sell_max: float = None, condition_buy_max: Any = None, condition_sell_max: Any = None) -> None:
75+
"""Used to set an indicator where one indicator crosses above or below a certain numerical threshold.
7476
7577
Arguments:
7678
----
@@ -102,7 +104,8 @@ def set_indicator_signal(self, indicator: str, buy: float, sell: float, conditio
102104
# Add the key if it doesn't exist.
103105
if indicator not in self._indicator_signals:
104106
self._indicator_signals[indicator] = {}
105-
107+
self._indicators_key.append(indicator)
108+
106109
# Add the signals.
107110
self._indicator_signals[indicator]['buy'] = buy
108111
self._indicator_signals[indicator]['sell'] = sell
@@ -115,6 +118,52 @@ def set_indicator_signal(self, indicator: str, buy: float, sell: float, conditio
115118
self._indicator_signals[indicator]['buy_operator_max'] = condition_buy_max
116119
self._indicator_signals[indicator]['sell_operator_max'] = condition_sell_max
117120

121+
def set_indicator_signal_compare(self, indicator_1: str, indicator_2: str, condition_buy: Any, condition_sell: Any) -> None:
122+
"""Used to set an indicator where one indicator is compared to another indicator.
123+
124+
Overview:
125+
----
126+
Some trading strategies depend on comparing one indicator to another indicator.
127+
For example, the Simple Moving Average crossing above or below the Exponential
128+
Moving Average. This will be used to help build those strategies that depend
129+
on this type of structure.
130+
131+
Arguments:
132+
----
133+
indicator_1 {str} -- The first indicator key, for example `ema` or `sma`.
134+
135+
indicator_2 {str} -- The second indicator key, this is the indicator we will compare to. For example,
136+
is the `sma` greater than the `ema`.
137+
138+
condition_buy {str} -- The operator which is used to evaluate the `buy` condition. For example, `">"` would
139+
represent greater than or from the `operator` module it would represent `operator.gt`.
140+
141+
condition_sell {str} -- The operator which is used to evaluate the `sell` condition. For example, `">"` would
142+
represent greater than or from the `operator` module it would represent `operator.gt`.
143+
"""
144+
145+
# Define the key.
146+
key = "{ind_1}_comp_{ind_2}".format(
147+
ind_1=indicator_1,
148+
ind_2=indicator_2
149+
)
150+
151+
# Add the key if it doesn't exist.
152+
if key not in self._indicator_signals:
153+
self._indicator_signals[key] = {}
154+
self._indicators_comp_key.append(key)
155+
156+
# Grab the dictionary.
157+
indicator_dict = self._indicator_signals[key]
158+
159+
# Add the signals.
160+
indicator_dict['type'] = 'comparison'
161+
indicator_dict['indicator_1'] = indicator_1
162+
indicator_dict['indicator_2'] = indicator_2
163+
indicator_dict['buy_operator'] = condition_buy
164+
indicator_dict['sell_operator'] = condition_sell
165+
166+
118167
@property
119168
def price_data_frame(self) -> pd.DataFrame:
120169
"""Return the raw Pandas Dataframe Object.
@@ -1010,6 +1059,9 @@ def refresh(self):
10101059

10111060
# Update the function.
10121061
indicator_function(**indicator_argument)
1062+
1063+
def grab_comparison_indicator(self) -> dict:
1064+
pass
10131065

10141066
def check_signals(self) -> Union[pd.DataFrame, None]:
10151067
"""Checks to see if any signals have been generated.
@@ -1020,7 +1072,11 @@ def check_signals(self) -> Union[pd.DataFrame, None]:
10201072
is returned otherwise nothing is returned.
10211073
"""
10221074

1023-
signals_df = self._stock_frame._check_signals(indicators=self._indicator_signals)
1075+
signals_df = self._stock_frame._check_signals(
1076+
indicators=self._indicator_signals,
1077+
indciators_comp_key=self._indicators_comp_key,
1078+
indicators_key=self._indicators_key
1079+
)
10241080

10251081
return signals_df
10261082

pyrobot/robot.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import pprint
44
import pathlib
55
import pandas as pd
6-
import pkg_resources
76

87
from datetime import time
98
from datetime import datetime
@@ -19,15 +18,11 @@
1918
from pyrobot.portfolio import Portfolio
2019
from pyrobot.stock_frame import StockFrame
2120

22-
current_td_version = pkg_resources.get_distribution('td-ameritrade-python-api').version
23-
2421
from td.client import TDClient
22+
from td.utils import TDUtilities
2523

26-
if current_td_version == '0.3.0':
27-
from td.utils import TDUtilities
28-
milliseconds_since_epoch = TDUtilities().milliseconds_since_epoch
29-
else:
30-
from td.utils import milliseconds_since_epoch
24+
# We are going to be doing some timestamp conversions.
25+
milliseconds_since_epoch = TDUtilities().milliseconds_since_epoch
3126

3227

3328
class PyRobot():
@@ -557,8 +552,8 @@ def get_latest_bar(self) -> List[dict]:
557552
bar_type = self._bar_type
558553

559554
# Define the start and end date.
560-
start_date = datetime.today()
561-
end_date = start_date - timedelta(minutes=bar_size * 15)
555+
end_date = datetime.today()
556+
start_date = end_date - timedelta(days=1)
562557
start = str(milliseconds_since_epoch(dt_object=start_date))
563558
end = str(milliseconds_since_epoch(dt_object=end_date))
564559

@@ -636,11 +631,11 @@ def wait_till_next_bar(self, last_bar_timestamp: pd.DatetimeIndex) -> None:
636631
print("-"*80)
637632
print("Curr Time: {time_curr}".format(
638633
time_curr=curr_bar_time.strftime("%Y-%m-%d %H:%M:%S")
639-
)
634+
)
640635
)
641636
print("Next Time: {time_next}".format(
642637
time_next=next_bar_time.strftime("%Y-%m-%d %H:%M:%S")
643-
)
638+
)
644639
)
645640
print("Sleep Time: {seconds}".format(seconds=time_to_wait_now))
646641
print("-"*80)
@@ -691,8 +686,8 @@ def execute_signals(self, signals: List[pd.Series], trades_to_execute: dict) ->
691686
}
692687
>>> signals = indicator_client.check_signals()
693688
>>> trading_robot.execute_signals(
694-
signals=signals,
695-
trades_to_execute=trades_dict
689+
signals=signals,
690+
trades_to_execute=trades_dict
696691
)
697692
"""
698693

0 commit comments

Comments
 (0)