Skip to content

Commit 2d61fb1

Browse files
committed
Add indicators, positions and orders, and properties
1 parent dbc2dde commit 2d61fb1

9 files changed

Lines changed: 846 additions & 81 deletions

File tree

data/orders.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6107,5 +6107,46 @@
61076107
]
61086108
},
61096109
"timestamp": "2020-06-12T09:09:07.137470"
6110+
},
6111+
{
6112+
"order_id": "MSFT_short_enter_1594053888.673015",
6113+
"request_body": {
6114+
"orderStrategyType": "TRIGGER",
6115+
"orderType": "LIMIT",
6116+
"session": "AM",
6117+
"duration": "GOOD_TILL_CANCEL",
6118+
"orderLegCollection": [
6119+
{
6120+
"instruction": "SELL_SHORT",
6121+
"quantity": 2,
6122+
"instrument": {
6123+
"symbol": "MSFT",
6124+
"assetType": "EQUITY"
6125+
}
6126+
}
6127+
],
6128+
"price": 150.0,
6129+
"cancelTime": "2020-07-06T09:44:38.686107",
6130+
"childOrderStrategies": [
6131+
{
6132+
"orderType": "STOP",
6133+
"session": "NORMAL",
6134+
"duration": "DAY",
6135+
"stopPrice": 149.9,
6136+
"orderStrategyType": "SINGLE",
6137+
"orderLegCollection": [
6138+
{
6139+
"instruction": "BUY_TO_COVER",
6140+
"quantity": 2,
6141+
"instrument": {
6142+
"symbol": "MSFT",
6143+
"assetType": "EQUITY"
6144+
}
6145+
}
6146+
]
6147+
}
6148+
]
6149+
},
6150+
"timestamp": "2020-07-06T09:44:48.673015"
61106151
}
61116152
]

pyrobot/indicators.py

Lines changed: 183 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ def get_indicator_signal(self, indicator: Optional[str]= None) -> Dict:
6868
return self._indicator_signals
6969

7070

71-
def set_indicator_signal(self, indicator: str, buy: float, sell: float, condition_buy: Any, condition_sell: Any) -> None:
71+
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:
7273
"""Return the raw Pandas Dataframe Object.
7374
7475
Arguments:
@@ -79,11 +80,23 @@ def set_indicator_signal(self, indicator: str, buy: float, sell: float, conditio
7980
8081
sell {float} -- The sell signal threshold for the indicator.
8182
82-
condition_buy {str} -- The operator which is used to evaluate the buy condition. For example, `">"` would
83+
condition_buy {str} -- The operator which is used to evaluate the `buy` condition. For example, `">"` would
8384
represent greater than or from the `operator` module it would represent `operator.gt`.
8485
85-
condition_buy {str} -- The operator which is used to evaluate the sell condition. For example, `">"` would
86+
condition_sell {str} -- The operator which is used to evaluate the `sell` condition. For example, `">"` would
8687
represent greater than or from the `operator` module it would represent `operator.gt`.
88+
89+
buy_max {float} -- If the buy threshold has a maximum value that needs to be set, then set the `buy_max` threshold.
90+
This means if the signal exceeds this amount it WILL NOT PURCHASE THE INSTRUMENT. (defaults to None).
91+
92+
sell_max {float} -- If the sell threshold has a maximum value that needs to be set, then set the `buy_max` threshold.
93+
This means if the signal exceeds this amount it WILL NOT SELL THE INSTRUMENT. (defaults to None).
94+
95+
condition_buy_max {str} -- The operator which is used to evaluate the `buy_max` condition. For example, `">"` would
96+
represent greater than or from the `operator` module it would represent `operator.gt`. (defaults to None).
97+
98+
condition_sell_max {str} -- The operator which is used to evaluate the `sell_max` condition. For example, `">"` would
99+
represent greater than or from the `operator` module it would represent `operator.gt`. (defaults to None).
87100
"""
88101

89102
# Add the key if it doesn't exist.
@@ -96,6 +109,12 @@ def set_indicator_signal(self, indicator: str, buy: float, sell: float, conditio
96109
self._indicator_signals[indicator]['buy_operator'] = condition_buy
97110
self._indicator_signals[indicator]['sell_operator'] = condition_sell
98111

112+
# Add the max signals
113+
self._indicator_signals[indicator]['buy_max'] = buy_max
114+
self._indicator_signals[indicator]['sell_max'] = sell_max
115+
self._indicator_signals[indicator]['buy_operator_max'] = condition_buy_max
116+
self._indicator_signals[indicator]['sell_operator_max'] = condition_sell_max
117+
99118
@property
100119
def price_data_frame(self) -> pd.DataFrame:
101120
"""Return the raw Pandas Dataframe Object.
@@ -562,6 +581,167 @@ def macd(self, fast_period: int = 12, slow_period: int = 26) -> pd.DataFrame:
562581

563582
return self._frame
564583

584+
def mass_index(self, period: int = 9) -> pd.DataFrame:
585+
"""Calculates the Mass Index indicator.
586+
587+
Arguments:
588+
----
589+
period {int} -- The number of periods to use when calculating
590+
the mass index. (default: {9})
591+
592+
Returns:
593+
----
594+
{pd.DataFrame} -- A Pandas data frame with the Mass Index included.
595+
596+
Usage:
597+
----
598+
>>> historical_prices_df = trading_robot.grab_historical_prices(
599+
start=start_date,
600+
end=end_date,
601+
bar_size=1,
602+
bar_type='minute'
603+
)
604+
>>> price_data_frame = pd.DataFrame(data=historical_prices)
605+
>>> indicator_client = Indicators(price_data_frame=price_data_frame)
606+
>>> indicator_client.mass_index(period=9)
607+
"""
608+
609+
locals_data = locals()
610+
del locals_data['self']
611+
612+
column_name = 'mass_index'
613+
self._current_indicators[column_name] = {}
614+
self._current_indicators[column_name]['args'] = locals_data
615+
self._current_indicators[column_name]['func'] = self.mass_index
616+
617+
# Calculate the Diff.
618+
self._frame['diff'] = self._frame['high'] - self._frame['low']
619+
620+
# Calculate Mass Index 1
621+
self._frame['mass_index_1'] = self._frame['diff'].transform(
622+
lambda x: x.ewm(span = period, min_periods = period - 1).mean()
623+
)
624+
625+
# Calculate Mass Index 2
626+
self._frame['mass_index_2'] = self._frame['mass_index_1'].transform(
627+
lambda x: x.ewm(span = period, min_periods = period - 1).mean()
628+
)
629+
630+
# Grab the raw index.
631+
self._frame['mass_index_raw'] = self._frame['mass_index_1'] / self._frame['mass_index_2']
632+
633+
# Calculate the Mass Index.
634+
self._frame['mass_index'] = self._frame['mass_index_raw'].transform(
635+
lambda x: x.rolling(window=25).sum()
636+
)
637+
638+
# Clean up before sending back.
639+
self._frame.drop(
640+
labels=['diff', 'mass_index_1', 'mass_index_2', 'mass_index_raw'],
641+
axis=1,
642+
inplace=True
643+
)
644+
645+
return self._frame
646+
647+
def kst_oscillator(self, r1: int, r2: int, r3: int, r4: int, n1: int, n2: int, n3: int, n4: int) -> pd.DataFrame:
648+
"""Calculates the Mass Index indicator.
649+
650+
Arguments:
651+
----
652+
period {int} -- The number of periods to use when calculating
653+
the mass index. (default: {9})
654+
655+
Returns:
656+
----
657+
{pd.DataFrame} -- A Pandas data frame with the Mass Index included.
658+
659+
Usage:
660+
----
661+
>>> historical_prices_df = trading_robot.grab_historical_prices(
662+
start=start_date,
663+
end=end_date,
664+
bar_size=1,
665+
bar_type='minute'
666+
)
667+
>>> price_data_frame = pd.DataFrame(data=historical_prices)
668+
>>> indicator_client = Indicators(price_data_frame=price_data_frame)
669+
>>> indicator_client.mass_index(period=9)
670+
"""
671+
672+
locals_data = locals()
673+
del locals_data['self']
674+
675+
column_name = 'kst_oscillator'
676+
self._current_indicators[column_name] = {}
677+
self._current_indicators[column_name]['args'] = locals_data
678+
self._current_indicators[column_name]['func'] = self.kst_oscillator
679+
680+
# Calculate the ROC 1.
681+
self._frame['roc_1'] = self._frame['close'].diff(r1 - 1) / self._frame['close'].shift(r1 - 1)
682+
683+
# Calculate the ROC 2.
684+
self._frame['roc_2'] = self._frame['close'].diff(r2 - 1) / self._frame['close'].shift(r2 - 1)
685+
686+
# Calculate the ROC 3.
687+
self._frame['roc_3'] = self._frame['close'].diff(r3 - 1) / self._frame['close'].shift(r3 - 1)
688+
689+
# Calculate the ROC 4.
690+
self._frame['roc_4'] = self._frame['close'].diff(r4 - 1) / self._frame['close'].shift(r4 - 1)
691+
692+
693+
# Calculate the Mass Index.
694+
self._frame['roc_1_n'] = self._frame['roc_1'].transform(
695+
lambda x: x.rolling(window=n1).sum()
696+
)
697+
698+
# Calculate the Mass Index.
699+
self._frame['roc_2_n'] = self._frame['roc_2'].transform(
700+
lambda x: x.rolling(window=n2).sum()
701+
)
702+
703+
# Calculate the Mass Index.
704+
self._frame['roc_3_n'] = self._frame['roc_3'].transform(
705+
lambda x: x.rolling(window=n3).sum()
706+
)
707+
708+
# Calculate the Mass Index.
709+
self._frame['roc_4_n'] = self._frame['roc_4'].transform(
710+
lambda x: x.rolling(window=n4).sum()
711+
)
712+
713+
self._frame[column_name] = 100 * (self._frame['roc_1_n'] + 2 * self._frame['roc_2_n'] + 3 * self._frame['roc_3_n'] + 4 * self._frame['roc_4_n'])
714+
self._frame[column_name + "_signal"] = self._frame['column_name'].transform(
715+
lambda x: x.rolling().mean()
716+
)
717+
718+
# Clean up before sending back.
719+
self._frame.drop(
720+
labels=['roc_1', 'roc_2', 'roc_3', 'roc_4', 'roc_1_n', 'roc_2_n', 'roc_3_n', 'roc_4_n'],
721+
axis=1,
722+
inplace=True
723+
)
724+
725+
return self._frame
726+
727+
# #KST Oscillator
728+
# def KST(df, r1, r2, r3, r4, n1, n2, n3, n4):
729+
# M = df['Close'].diff(r1 - 1)
730+
# N = df['Close'].shift(r1 - 1)
731+
# ROC1 = M / N
732+
# M = df['Close'].diff(r2 - 1)
733+
# N = df['Close'].shift(r2 - 1)
734+
# ROC2 = M / N
735+
# M = df['Close'].diff(r3 - 1)
736+
# N = df['Close'].shift(r3 - 1)
737+
# ROC3 = M / N
738+
# M = df['Close'].diff(r4 - 1)
739+
# N = df['Close'].shift(r4 - 1)
740+
# ROC4 = M / N
741+
# KST = pd.Series(pd.rolling_sum(ROC1, n1) + pd.rolling_sum(ROC2, n2) * 2 + pd.rolling_sum(ROC3, n3) * 3 + pd.rolling_sum(ROC4, n4) * 4, name = 'KST_' + str(r1) + '_' + str(r2) + '_' + str(r3) + '_' + str(r4) + '_' + str(n1) + '_' + str(n2) + '_' + str(n3) + '_' + str(n4))
742+
# df = df.join(KST)
743+
# return df
744+
565745
def refresh(self):
566746
"""Updates the Indicator columns after adding the new rows."""
567747

pyrobot/portfolio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def add_positions(self, positions: List[dict]) -> dict:
5252
5353
Usage:
5454
----
55-
# Define mutliple positions to add.
55+
>>> # Define mutliple positions to add.
5656
>>> multi_position = [
5757
{
5858
'asset_type': 'equity',

0 commit comments

Comments
 (0)