def get_xy_parameter_for_replay_list(tick_list: list, replay_process: str): x = [tick.time_stamp for tick in tick_list] y = [] for tick in tick_list: y_value_dict = { TSP.WATCHING: tick.watch_breakout_value, TSP.BUYING: tick.breakout_value, TSP.SELLING: tick.limit_value, TSP.RE_BUYING: tick.limit_value } y.append(MyMath.round_smart(y_value_dict[replay_process])) # y = [round(tick.breakout_value, 4) if for_buying else round(tick.limit_value, 4) for tick in tick_list] for tick in reversed(tick_list): x.append(tick.time_stamp) y_value_dict = { TSP.WATCHING: tick.watch_wrong_breakout_value, TSP.BUYING: tick.wrong_breakout_value, TSP.SELLING: tick.stop_loss_value, TSP.RE_BUYING: tick.stop_loss_value } y.append(MyMath.round_smart(y_value_dict[replay_process])) # y.append(round(tick.wrong_breakout_value, 4) if for_buying else round(tick.stop_loss_value, 4)) # print('list(zip(x, y))={}'.format(list(zip(x, y)))) return list(zip(x, y))
def correct_data_types_withing_data_dict_list(self, table_name: str, input_dict_list): table = self.get_table_by_name(table_name) for data_dict in input_dict_list: for column_name, value in data_dict.items(): column = table.get_column(column_name) if column is not None: if column.is_integer: data_dict[column_name] = int( MyMath.get_float_for_string(value)) elif column.is_boolean: if value == 'True': data_dict[column_name] = True elif value == 'False': data_dict[column_name] = False elif column.is_float: if MyText.is_number(value): data_dict[ column_name] = MyMath.get_float_for_string( value) elif column.is_date: if MyText.is_date_time_date(value): data_dict[column_name] = MyText.get_date_time_date( value) elif column.is_time: if MyText.is_date_time_time(value): data_dict[column_name] = MyText.get_date_time_time( value)
def add_row_specific_styles_to_table_style_data(rows, table_style_data): column_id = DC.ACTUAL fractions = 5 color_dict = { 1: 'orange', 2: 'bisque', 3: 'ivory', 4: 'lightgreen', 5: 'lime' } for row in rows: if row[DC.ID] != '': actual_price = MyMath.get_float_for_string(row[DC.ACTUAL]) stop = MyMath.get_float_for_string(row[DC.STOP]) limit = stop * 1.05 if row[ DC.LIMIT] == 'inf' else MyMath.get_float_for_string( row[DC.LIMIT]) if actual_price <= stop: bg_color = 'red' else: bg_color = 'green' value_range = limit - stop value_range_fraction = value_range / fractions for i in range(1, fractions + 1): if actual_price <= stop + i * value_range_fraction: bg_color = color_dict[i] break filter_color = '{{{}}} eq "{}"'.format(DC.ID, row[DC.ID]) table_style_data.append({ 'if': { 'column_id': column_id, 'filter': filter_color }, 'backgroundColor': bg_color })
def get_markdown_text_for_last_wave_tick(self, volume_mean=0, period=PRD.INTRADAY): prev_tick = self.tick_list[-2] actual_tick = self.tick_list[-1] prefix = actual_tick.time if period == PRD.INTRADAY else actual_tick.date forecast_volume = MyMath.round_smart( actual_tick.get_forecast_volume(self.tick_distance_in_seconds)) if prev_tick.volume == 0: volume_change_against_last = 0 else: volume_change_against_last = MyMath.round_smart( forecast_volume / prev_tick.volume * 100 - 100) if volume_mean == 0: forecast_values = '{} ({:+.0f} %)'.format( forecast_volume, volume_change_against_last) else: volume_change_against_mean = MyMath.round_smart(forecast_volume / volume_mean * 100 - 100) forecast_values = '{} ({:+.0f} % / {:+.0f} %)'.format( forecast_volume, volume_change_against_mean, volume_change_against_last) return '**{}:** open={}, close={}, volume={}, volume forecast={}'. \ format(prefix, actual_tick.open, actual_tick.close, actual_tick.volume, forecast_values)
def get_lower_value(self, f_var: float, with_smart_rounding=False): if with_smart_rounding: if f_var < self.tick_for_helper.f_var: return MyMath.round_smart(self._f_lower(f_var)) return MyMath.round_smart(self._h_lower(f_var)) if f_var < self.tick_for_helper.f_var: return round(self._f_lower(f_var), 4) return round(self._h_lower(f_var), 4)
def get_upper_value(self, f_var: int, with_smart_rounding=False): if with_smart_rounding or True: if f_var < self.tick_for_helper.f_var: return MyMath.round_smart(self._f_upper(f_var)) return MyMath.round_smart(self._h_upper(f_var)) if f_var < self.tick_for_helper.f_var: return round(self._f_upper(f_var), 4) return round(self._h_upper(f_var), 4)
def __get_retracement_predictor_value__(self) -> float: if self.valid_wave is None: return 0 fc_value_regression = self.retracement_end_parameters_regression[1] fc_value_classifier = self.retracement_end_parameters_classifier[1] min_fc_value = min(fc_value_regression, fc_value_classifier) max_fc_value = max(fc_value_regression, fc_value_classifier) # print('min_fc_value={}, max_fc_value={}'.format(min_fc_value, max_fc_value)) return MyMath.round_smart(min_fc_value) if self.pattern_type == FT.FIBONACCI_DESC \ else MyMath.round_smart(max_fc_value)
def __calculate_thresholds__(self): q75, q25 = np.percentile(self._values, [75, 25]) iqr = q75 - q25 self._bottom_threshold_iqr = MyMath.round_smart(q25 - 1.5 * iqr) self._top_threshold_iqr = MyMath.round_smart(q75 + 1.5 * iqr) if len(self._values) <= 4: self._bottom_threshold = self._bottom_threshold_iqr self._top_threshold = self._top_threshold_iqr else: self._bottom_threshold = MyMath.round_smart( np.percentile(self._values, self._threshold_pct)) self._top_threshold = MyMath.round_smart( np.percentile(self._values, 100 - self._threshold_pct))
def is_volume_rising(self, min_percentage: int): # we check raising against mean volume and against last tick volume - either of both. # print('is_volume_rising: volume_forecast={}, volume_meanPart_entry={}, min_percentage={}, p_volume={}'.format( # self.volume_forecast, self.volume_mean_part_entry, min_percentage, self.tick_previous.volume # )) if self.volume_mean_part_entry == 0: # we don't have volume information like for FOREX return True against_mean = MyMath.divide( self.volume_forecast, self.volume_mean_part_entry) > (100 + min_percentage) / 100 against_last = MyMath.divide( self.volume_forecast, self.tick_previous.volume) > (100 + min_percentage) / 100 return against_mean or against_last
def __is_f_param_boundary_compliant__(self, f_param: np.poly1d, f_param_boundary: np.poly1d) -> bool: offset = self.tick_list[0].f_var slope_dec_main = MyPoly1d.get_slope_in_decimal_percentage( f_param, offset, self.length) slope_dec_bound = MyPoly1d.get_slope_in_decimal_percentage( f_param_boundary, offset, self.length) if f_param(offset) > f_param_boundary(offset): slope_main_bound = MyMath.round_smart(slope_dec_main - slope_dec_bound) else: slope_main_bound = MyMath.round_smart(slope_dec_bound - slope_dec_main) return slope_main_bound < 0.04 # we don't accept wide opening patterns
def set_fee_amount(self, fee_value: float, as_pct=False): amount = self.original_amount if self.executed_amount == 0 else self.executed_amount if as_pct: self._fee_amount = MyMath.round_smart(self.price * amount * fee_value / 100) else: self._fee_amount = fee_value
def __get_mean_forecast_wave_end_pct__(self): if self.are_valid_waves_available: return MyMath.round_smart( statistics.mean([ wave.forecast_wave_end_pct for wave in self.valid_wave_list ]) * 100) return 0
def __is_relation_heights_compliant__(self, height_end: float, height_start: float): if len(self.height_end_start_relation_bounds) == 0: # no relation defined return True if height_start == 0: return False end_start_relation = MyMath.divide(height_end, height_start) return self.height_end_start_relation_bounds[0] <= end_start_relation <= self.height_end_start_relation_bounds[1]
def __get_mean_forecast_retracement_pct__(self) -> float: if self.are_valid_waves_available: retracement_pct_list = [ wave.forecast_value_retracement_pct for wave in self.valid_wave_list ] return MyMath.round_smart(statistics.mean(retracement_pct_list)) return 0
def __init__(self, api: PatternBreakoutApi): self.sys_config = api.sys_config self.function_cont = api.function_cont self.constraints = api.constraints self.tick_previous = api.tick_previous self.tick_breakout = api.tick_breakout self.volume_mean_part_entry = api.volume_mean_for_breakout self.volume_forecast = api.volume_forecast self.breakout_date = self.tick_breakout.date self.volume_change_pct = MyMath.divide(self.tick_breakout.volume, self.tick_previous.volume, 2, 0) self.tolerance_pct = self.constraints.tolerance_pct self.bound_upper = MyMath.round_smart( self.function_cont.get_upper_value(self.tick_breakout.f_var)) self.bound_lower = MyMath.round_smart( self.function_cont.get_lower_value(self.tick_breakout.f_var)) self.pattern_breadth = MyMath.round_smart(self.bound_upper - self.bound_lower) self.tolerance_range = MyMath.round_smart(self.pattern_breadth * self.tolerance_pct) self.limit_upper = MyMath.round_smart(self.bound_upper + self.tolerance_range) self.limit_lower = MyMath.round_smart(self.bound_lower - self.tolerance_range) if api.forecast_breakout_direction == FD.NONE: self.breakout_direction = self.__get_breakout_direction__() else: self.breakout_direction = api.forecast_breakout_direction self.sign = 1 if self.breakout_direction == FD.ASC else -1 self.check_dict = {}
def get_xy_parameter_for_tick_function_list(tick_list: list, func_list, closed: bool = True): x = [tick.f_var for tick in tick_list] y = [ MyMath.round_smart(func(tick_list[ind].f_var)) for ind, func in enumerate(func_list) ] return list(zip(x, y))
def get_details_for_annotations(self): if self.sys_config.period == PRD.INTRADAY: date_str = self.tick_breakout.time_str_for_f_var else: date_str = self.tick_breakout.date_str_for_f_var vol_change = (MyMath.divide(self.volume_forecast, self.volume_mean_part_entry, 2) - 1) * 100 return '{} ({}) - Volume change: {}%'.format( date_str, self.tick_breakout.position, round(vol_change, 0))
def __get_rounded_value__(key, value): if key in [SLDC.PRICE, SLDC.PRICE_SINGLE, SLDC.PRICE_ORIGINAL]: try: return MyMath.round_smart(value) except: print('SalesmanDataDictionary: Error for {}={}'.format( key, value)) return 0 return value
def add_row_specific_styles_to_table_style_data(rows, table_style_data): column_id = PDC.AMOUNT_AVAILABLE for row in rows: if row[PDC.EXCHANGE] != '': amount = MyMath.get_float_for_string(row[PDC.AMOUNT]) amount_available = MyMath.get_float_for_string( row[PDC.AMOUNT_AVAILABLE]) if amount != amount_available: bg_color = 'bisque' filter_color = '{{{}}} eq "{}"'.format( PDC.ASSET, row[PDC.ASSET]) table_style_data.append({ 'if': { 'column_id': column_id, 'filter': filter_color }, 'backgroundColor': bg_color })
def __add_observation_specific_columns_to_data_dict__(self): self._entity_data_dict[POC.LIMIT_PCT] = self.__get_limit_pct__() self._entity_data_dict[ POC.STOP_LOSS_PCT] = self.__get_stop_loss_pct__() self._entity_data_dict[POC.CURRENT_TICK_PCT] = 0 self._entity_data_dict[POC.CURRENT_VALUE_HIGH_PCT] = 0 self._entity_data_dict[POC.CURRENT_VALUE_LOW_PCT] = 0 self._entity_data_dict[POC.CURRENT_VALUE_OPEN_PCT] = 0 self._entity_data_dict[POC.CURRENT_VALUE_CLOSE_PCT] = 0 self._entity_data_dict[POC.CURRENT_VOLUME_BUY_PCT] = 0 self._entity_data_dict[POC.CURRENT_VOLUME_LAST_PCT] = 0 self._entity_data_dict[ POC.BEFORE_PATTERN_MAX_PCT] = MyMath.get_change_in_percentage( self.buy_price, self.wave_tick_list_before_pattern.df[CN.HIGH].max()) self._entity_data_dict[ POC.BEFORE_PATTERN_MIN_PCT] = MyMath.get_change_in_percentage( self.buy_price, self.wave_tick_list_before_pattern.df[CN.LOW].min()) self._entity_data_dict[ POC.PATTERN_MAX_PCT] = MyMath.get_change_in_percentage( self.buy_price, self.wave_tick_list_pattern.df[CN.HIGH].max()) self._entity_data_dict[ POC.PATTERN_MIN_PCT] = MyMath.get_change_in_percentage( self.buy_price, self.wave_tick_list_pattern.df[CN.LOW].min()) self._entity_data_dict[POC.AFTER_BUY_MAX_PCT] = 0 self._entity_data_dict[POC.AFTER_BUY_MIN_PCT] = 0 self._entity_data_dict[ POC. FC_TICKS_TO_POSITIVE_HALF_PCT] = self.__get_forecast_ticks_as_pct__( DC.FC_TICKS_TO_POSITIVE_HALF) self._entity_data_dict[ POC. FC_TICKS_TO_POSITIVE_FULL_PCT] = self.__get_forecast_ticks_as_pct__( DC.FC_TICKS_TO_POSITIVE_FULL) self._entity_data_dict[ POC. FC_TICKS_TO_NEGATIVE_HALF_PCT] = self.__get_forecast_ticks_as_pct__( DC.FC_TICKS_TO_NEGATIVE_HALF) self._entity_data_dict[ POC. FC_TICKS_TO_NEGATIVE_FULL_PCT] = self.__get_forecast_ticks_as_pct__( DC.FC_TICKS_TO_NEGATIVE_FULL)
def get_slope(self, pos_start: int, pos_end: int, df_col: str = CN.CLOSE): df_part = self.df.iloc[pos_start:pos_end + 1] # print('get_slope: pos_start={}, pos_end={}, df_col={}, df_part.shape[0]={}'.format( # pos_start, pos_end, df_col, df_part.shape[0])) tick_first = WaveTick(df_part.iloc[0]) tick_last = WaveTick(df_part.iloc[-1]) stock_df = PatternDataFrame(df_part) func = stock_df.get_f_regression(df_col) offset_value = df_part[df_col].mean() return MyMath.get_change_in_percentage(func(tick_first.f_var), func(tick_last.f_var), offset_value=offset_value)
def get_tolerance_pct_values(self): if self.pattern_data.df.shape[0] <= 1: print( 'get_tolerance_pct_values: we have only one row - returning 0, 0, 0' ) return 0, 0, 0 mean_hl = MyMath.round_smart(self.pattern_data.df[CN.MEAN_HL].mean()) if mean_hl == 0 or mean_hl == math.nan: return 0, 0, 0 std_dev_mean_hl = MyMath.round_smart( self.pattern_data.df[CN.MEAN_HL].std()) base_tolerance_pct = MyMath.round_smart(std_dev_mean_hl / mean_hl) tolerance_pct = base_tolerance_pct / 5 tolerance_pct_equal = tolerance_pct / 2 tolerance_pct_buying = 0 # tolerance_pct / 2 print( 'tolerance_pct={:.2f}%, tolerance_pct_equal={:.2f}%, tolerance_pct_buying={:.2f}%' .format(tolerance_pct * 100, tolerance_pct_equal * 100, tolerance_pct_buying * 100)) return tolerance_pct, tolerance_pct_equal, tolerance_pct_buying
def __get_corrected_value__(key: str, value): if key == SLDC.TITLE: return value.replace('/', ' / ') if type(key) is str else value elif key == SLDC.PRICE: if type(value) is str: return MyMath.get_float_for_string(value) elif key == SLDC.START_DATE: return MyDate.get_date_str_for_date_term(value) elif key in [SLDC.VISITS, SLDC.BOOK_MARKS]: if type(value) is str: return int(value.split(' ')[0]) return value
def __calculate_reward__(self, done: bool, obs: TradeObservation, step: EnvironmentStep): if done: step.reward = obs.current_value_open_pct date = obs.wave_tick.date sold_price = MyMath.get_value_from_percentage_on_base_value( step.reward, self.off_set_value) step.info_dict[ 'SOLD'] = '{:.2f} ({}) - bought: {:.2f} ({})'.format( sold_price, date, self.off_set_value, self.off_set_date) else: step.reward = -0.01
def __calculate_variables__(self, by_iqr=False): self._min_values = MyMath.round_smart(min(self._values)) self._max_values = MyMath.round_smart(max(self._values)) self._mean_values = MyMath.round_smart(statistics.mean(self._values)) self.__calculate_thresholds__() for value in self._values: if not self.is_value_outlier(value): self._values_without_outliers.append(value) if not self.is_value_iqr_outlier(value): self._values_without_iqr_outliers.append(value) if len(self._values_without_outliers) == 0: self._mean_values_without_outliers = 0 else: self._mean_values_without_outliers = \ MyMath.round_smart(statistics.mean(self._values_without_outliers)) if len(self._values_without_iqr_outliers) == 0: self._mean_values_without_iqr_outliers = 0 else: self._mean_values_without_iqr_outliers = \ MyMath.round_smart(statistics.mean(self._values_without_iqr_outliers))
def __calculate_regression_values_for_component__( self, reg_comp: FibonacciDescendingRegressionComponent): index_comp_id = self.comp_id_list_reg.index(reg_comp.comp_id) if index_comp_id > 0: reg_comp_prev = self.comp_dic[self.comp_id_list_reg[index_comp_id - 1]] ret_comp_prev = self.comp_dic[self.comp_id_list_ret[index_comp_id - 1]] reg_comp.regression_value_against_last_regression = round( reg_comp_prev.min - reg_comp.min, 2) reg_comp.regression_value_against_last_retracement = round( ret_comp_prev.min - reg_comp.min, 2) # if reg_comp_prev.get_end_to_end_range() == 0: # ToDo - why is this happen ??? # print('if reg_comp_prev.get_end_to_end_range() == 0') reg_comp.regression_pct_against_last_regression = \ MyMath.divide(reg_comp.get_end_to_end_range(), reg_comp_prev.get_end_to_end_range(), 3)
def __get_mean_parameters_from_xy_parameter_list__( xy_parameters_list: list): # we get a list of ...[(1556661600, 215.3), (1557375012, 154.46), (1559296128, 181.64), (1556661600, 215.3)] xy_parameters_return = [] for idx in (0, 1, 2): ts_list = [ xy_parameters[idx][0] for xy_parameters in xy_parameters_list ] value_list = [ xy_parameters[idx][1] for xy_parameters in xy_parameters_list ] ts_mean = int(statistics.mean(ts_list)) value_mean = MyMath.round_smart(statistics.mean(value_list)) xy_parameters_return.append((ts_mean, value_mean)) # print('xy_parameters_return={}'.format(xy_parameters_return)) return xy_parameters_return
def __init__(self, ticker_id: str, bid: float, ask: float, last_price: float, low: float, high: float, vol: float, ts: int): self.ticker_id = ticker_id self.bid = MyMath.round_smart(bid) self.ask = MyMath.round_smart(ask) self.last_price = MyMath.round_smart(last_price) self.low = MyMath.round_smart(low) self.high = MyMath.round_smart(high) self.vol = MyMath.round_smart(vol) self.time_stamp = round(ts)
def get_simple_moving_average(self, elements: int = 0, ts_breakout=0, default_value=0): """ The simple moving average is calculated in this way: a) For all ticks before the breakout we take the lower bound value = default_value b) For all others we take the low """ base_list = self.tick_list if elements == 0 else self.tick_list[ -elements:] base_list_reversed = base_list[::-1] value_list = [] for tick in base_list_reversed: if tick.time_stamp < ts_breakout: value_list.append(default_value) else: value_list.append(tick.open) return MyMath.round_smart(np.average(value_list))
def __adjust_observation_to_wave_tick__(self, obs: TradeObservation, wave_tick: WaveTick, wave_tick_previous: WaveTick): obs.wave_tick = wave_tick obs.current_value_high_pct = MyMath.get_change_in_percentage( self.off_set_value, wave_tick.high) obs.current_value_low_pct = MyMath.get_change_in_percentage( self.off_set_value, wave_tick.low) obs.current_value_open_pct = MyMath.get_change_in_percentage( self.off_set_value, wave_tick.open) obs.current_value_close_pct = MyMath.get_change_in_percentage( self.off_set_value, wave_tick.close) obs.current_volume_buy_pct = MyMath.get_change_in_percentage( self.off_set_volume, wave_tick.volume) obs.current_volume_last_pct = MyMath.get_change_in_percentage( wave_tick_previous.volume, wave_tick.volume)