Beispiel #1
0
    def get_no_of_shares(self,
                         capital: float,
                         pct_risk_per_trade: float,
                         volume_limit: float,
                         price: Series,
                         slippage: int = None,
                         is_slip_up: bool = True) -> int:
        if not AppConsts.PRICE_COL_OPEN in price.index \
                or not AppConsts.CUSTOM_COL_ADV in price.index:
            return 0
        open_price: float = price.loc[AppConsts.PRICE_COL_OPEN]
        if slippage:
            if is_slip_up:
                open_price = NumberUtils.round(open_price + (
                    open_price * AppConsts.BASIS_POINT * slippage))
            else:
                open_price = NumberUtils.round(open_price - (
                    open_price * AppConsts.BASIS_POINT * slippage))

        no_of_shares: int = NumberUtils.to_floor(capital * pct_risk_per_trade /
                                                 100 / open_price)
        adv: float = price.loc[AppConsts.CUSTOM_COL_ADV] if price.loc[
            AppConsts.CUSTOM_COL_ADV] > 0 else price.loc[
                AppConsts.PRICE_COL_VOLUME]
        max_volume: float = NumberUtils.to_int(adv * volume_limit / 100)
        if no_of_shares > max_volume:
            LogUtils.warning(
                'Capping max_volume adv={0}, no_of_shares={1}, max_volume={2}'.
                format(adv, no_of_shares, max_volume))
            no_of_shares = max_volume
        return no_of_shares
Beispiel #2
0
  def import_prices(self, limit: int = 100) -> int:
    results: Dict = {
        'stock_prices': [],
        'etf_prices': [],
        'missing_symbols': [],
        'errors': []
    }
    try:
      symbol_masters: List[SymbolMaster] = self.__stock_service.get_symbols(instrument='', exclude_status=[AppConsts.SYMBOL_STATUS_ARCHIVED])
      symbols: List[str] = [s.symbol for s in symbol_masters]
      price_set: BarSet = self.__alpaca_client.get_prices(symbols, limit)

      if not price_set:
        raise NotFoundException('BarSet', 'symbols', '')

      for symbol in symbol_masters:
        LogUtils.debug('start {0}'.format(symbol.symbol))

        prices: Bars = price_set[symbol.symbol]
        if not prices:
          LogUtils.warning('{0} price not found.'.format(symbol))
          results['missing_symbols'].append(symbol.symbol)
          continue

        for price in prices:
          price_date: datetime = price.t.to_pydatetime()
          data: tuple = (
              symbol.id,
              price_date,
              NumberUtils.to_float(price.o),
              NumberUtils.to_float(price.h),
              NumberUtils.to_float(price.l),
              NumberUtils.to_float(price.c),
              NumberUtils.to_int(price.v),
          )
          if symbol.instrument == AppConsts.INSTRUMENT_STOCK:
            org: StockPriceDaily = self.__stock_service.get_single_stock_price_daily(symbol.id, price_date)
            if not org:
              results['stock_prices'].append(data)
          else:
            org: EtfPriceDaily = self.__stock_service.get_single_etf_price_daily(symbol.id, price_date)
            if not org:
              results['etf_prices'].append(data)
      if results['stock_prices']:
        BaseService._insert_bulk(StockPriceDaily, results['stock_prices'])
      if results['etf_prices']:
        BaseService._insert_bulk(EtfPriceDaily, results['etf_prices'])
    except NotFoundException as ex:
      results['errors'].append(ex)
    except Exception as ex:
      results['errors'].append(ex)
    finally:
      self.__email_client.send_html(
          subject=AppConsts.EMAIL_SUBJECT_IMPORT_PRICES,
          template_path=AppConsts.TEMPLATE_PATH_IMPORT_PRICES,
          model=results)
      if results['errors']:
        for error in results['errors']:
          LogUtils.error('Import Price Error', error)
      return 1
Beispiel #3
0
 def get_dict(item: Any) -> Dict:
     ret: Dict = {}
     if not item:
         return ret
     for key, val in vars(item).items():
         key = key.lstrip('_')
         if isinstance(val, int):
             ret[key] = NumberUtils.to_int(val)
         elif isinstance(val, (Decimal, float)):
             ret[key] = NumberUtils.to_float(val)
         elif isinstance(val, (bool, np.bool_)):
             ret[key] = bool(val)
         elif isinstance(val, (datetime.date, datetime.datetime)):
             ret[key] = val.isoformat()
         elif isinstance(val, list):
             ret[key] = ModelUtils.get_dicts(val)
         elif isinstance(val, Dict):
             ret[key] = val
         elif isinstance(val, db.Model):
             ret[key] = ModelUtils.get_dict(val)
         elif isinstance(val, (BaseResponse, Entity)):
             ret[key] = ModelUtils.get_dict(val)
         else:
             ret[key] = str(val)
     return ret
Beispiel #4
0
    def import_from_csv_yahoo(self) -> str:
        BaseService._truncate(EPD)

        files: List[str] = FileUtils.get_files(AppConsts.ETF_PRICE_FOLDER,
                                               is_full=True)
        for file in files:
            symbol: str = FileUtils.get_wo_ext(FileUtils.get_base_name(file))
            org_symbol: SM = self.__stock_service.get_symbol(
                symbol, AppConsts.INSTRUMENT_ETF)
            if not org_symbol:
                continue
            records: List[Dict] = CsvUtils.parse_as_dict(file)
            models: List[Any] = []
            for record in records:
                models.append((
                    org_symbol.id,
                    DateUtils.get_date(record.get(AppConsts.YAHOO_KEY_DATE),
                                       AppConsts.YAHOO_DATE_FORMAT),
                    NumberUtils.to_float(record.get(AppConsts.YAHOO_KEY_OPEN)),
                    NumberUtils.to_float(record.get(AppConsts.YAHOO_KEY_HIGH)),
                    NumberUtils.to_float(record.get(AppConsts.YAHOO_KEY_LOW)),
                    NumberUtils.to_float(record.get(
                        AppConsts.YAHOO_KEY_CLOSE)),
                    NumberUtils.to_int(record.get(AppConsts.YAHOO_KEY_VOLUME)),
                ))
            BaseService._insert_bulk(EPD, models)
        return "1"
Beispiel #5
0
    def set_readonly_props(self) -> None:
        if not self._transactions:
            return

        self._start_capital = self._capital.get(
            ModelUtils.get_first_key(self._capital))
        self._end_capital = self._capital.get(
            ModelUtils.get_last_key(self._capital))
        self._hold_length_days_stats = StatUtils.get_descriptive_stats(
            [t.hold_length_days for t in self._transactions])
        self._change_in_capital_stats = StatUtils.get_descriptive_stats(
            [t.change_in_capital for t in self._transactions])
        self._has_profit_stats = StatUtils.get_descriptive_stats(
            [NumberUtils.to_int(t.has_profit) for t in self._transactions])
        self._pct_return = NumberUtils.get_change(self._end_capital,
                                                  self._start_capital)

        self._best_transactions = [
            t for t in sorted(self._transactions,
                              key=lambda x: x.change_in_capital,
                              reverse=True) if t.has_profit
        ][:20]
        self._worst_transactions = [
            t for t in sorted(self._transactions,
                              key=lambda x: x.change_in_capital)
            if not t.has_profit
        ][:20]

        symbol_grouped: Dict = {}
        for t in self._transactions:
            if not t.symbol_master.symbol in symbol_grouped:
                symbol_grouped[t.symbol_master.symbol]: Dict = {
                    'symbol_master': t.symbol_master,
                    'change_in_capital': 0,
                    'no_of_transactions': 0
                }
            symbol_grouped[t.symbol_master.
                           symbol]['change_in_capital'] += t.change_in_capital
            symbol_grouped[t.symbol_master.symbol]['no_of_transactions'] += 1

        symbol_grouped_list: List[BackTestResultItemPerSymbol] = []
        for k, v in symbol_grouped.items():
            item: BackTestResultItemPerSymbol = BackTestResultItemPerSymbol()
            item.symbol_master = symbol_grouped[k]['symbol_master']
            item.change_in_capital = NumberUtils.round(
                symbol_grouped[k]['change_in_capital'])
            item.no_of_transactions = symbol_grouped[k]['no_of_transactions']
            symbol_grouped_list.append(item)
        self._best_symbols = [
            i for i in sorted(symbol_grouped_list,
                              key=lambda x: x.change_in_capital,
                              reverse=True) if i.change_in_capital > 0
        ][:20]
        self._worst_symbols = [
            i for i in sorted(symbol_grouped_list,
                              key=lambda x: x.change_in_capital)
            if i.change_in_capital < 0
        ][:20]
Beispiel #6
0
    def get_all_suggestions(self) -> int:
        error: Exception = None
        try:

            accnt: Account = self.get_account()
            capital: float = NumberUtils.to_floor(
                NumberUtils.to_float(accnt._raw['buying_power']) /
                2)  # 2 to trade everyday

            # Double Bottoms
            req: TradeSuggestionsRequest = TradeSuggestionsRequest()
            req.is_job = True
            req.current_capital = capital
            req.pct_risk_per_trade = 2.5
            req.volume_limit = 0.01
            req.test_limit_symbol = 800
            req.adv_min = AppConsts.ADV_MIN_DFLT
            req.adpv_min = AppConsts.ADPV_MIN_DFLT
            req.strategy_type = AppConsts.STRATEGY_DOUBLE_BOTTOMS
            req.strategy_request = {}
            req.strategy_request['exponential_smoothing_alpha'] = 0.8
            req.strategy_request['exponential_smoothing_max_min_diff'] = 0.7
            req.strategy_request['double_bottoms_diff'] = 1
            LogUtils.debug(StringUtils.to_json(req))
            self.get_suggestions(req)

            # Double Tops
            req: TradeSuggestionsRequest = TradeSuggestionsRequest()
            req.is_job = True
            req.current_capital = capital
            req.pct_risk_per_trade = 2.5
            req.volume_limit = 0.01
            req.test_limit_symbol = 800
            req.adv_min = AppConsts.ADV_MIN_DFLT
            req.adpv_min = AppConsts.ADPV_MIN_DFLT
            req.strategy_type = AppConsts.STRATEGY_DOUBLE_TOPS
            req.strategy_request = {}
            req.strategy_request['exponential_smoothing_alpha'] = 0.8
            req.strategy_request['exponential_smoothing_max_min_diff'] = 0.7
            req.strategy_request['double_tops_diff'] = 1
            LogUtils.debug(StringUtils.to_json(req))
            self.get_suggestions(req)

        except Exception as ex:
            error = ex
        finally:
            self.__email_client.send_html(
                subject=AppConsts.EMAIL_SUBJECT_GET_SUGGESTIONS,
                template_path=AppConsts.TEMPLATE_PATH_GET_SUGGESTIONS,
                model={'errors': [error] if error else []})
            if error:
                LogUtils.error('Get Suggestions Error', error)
            return 1
Beispiel #7
0
 def import_from_csv_filedates(self) -> str:
     file: str = FileUtils.get_file(AppConsts.INCOME_STMT_FILE)
     records: List[Dict] = CsvUtils.parse_as_dict(file)
     for record in records:
         if not self.__is_valid_intrinio_record_for_filedates(record):
             continue
         symbol: str = record.get(AppConsts.INTRINIO_KEY_INC_STMT_TICKER)
         fiscal_period: str = record.get(
             AppConsts.INTRINIO_KEY_INC_STMT_FISC_PD)
         year: int = NumberUtils.to_int(
             record.get(AppConsts.INTRINIO_KEY_INC_STMT_FISC_YR))
         quarter: int = self.__get_quarter(fiscal_period)
         file_date: date = DateUtils.get_date(
             record.get(AppConsts.INTRINIO_KEY_INC_STMT_FILE_DTE),
             AppConsts.INTRINIO_FILE_DTE_FMT)
         if not file_date or quarter == 4:
             continue
         org_symbol: SM = self.__stock_service.get_symbol(
             symbol, AppConsts.INSTRUMENT_STOCK)
         if not org_symbol:
             continue
         org_fn: FN = self.__stock_service.get_financial(
             org_symbol.id, year, quarter)
         if not org_fn:
             continue
         org_fn.file_date = file_date
         BaseService._update()
     return "1"
Beispiel #8
0
 def __get_quarter(self, fiscal_period: str) -> int:
     if StringUtils.isNullOrWhitespace(fiscal_period):
         return None
     if fiscal_period.endswith(AppConsts.INTRINIO_PERIOD_SUFFIX_FY):
         return 4
     return NumberUtils.to_int(
         fiscal_period.replace(AppConsts.INTRINIO_PERIOD_PREFIX,
                               '').replace(
                                   AppConsts.INTRINIO_PERIOD_SUFFIX_TTM,
                                   ''))
Beispiel #9
0
    def append_abz(
            self,
            prices: DataFrame,
            index: Any,
            abz_er_period: int,
            abz_std_distance: float,
            abz_constant_k: float,
            target_column: str = AppConsts.PRICE_COL_CLOSE) -> DataFrame:
        if not isinstance(prices, DataFrame) \
                or not target_column in prices.columns:
            return None
        if not AppConsts.CUSTOM_COL_ABZ_PERIOD in prices.columns:
            prices[AppConsts.CUSTOM_COL_ABZ_PERIOD] = 0
        if not AppConsts.CUSTOM_COL_ABZ_MIDDLE in prices.columns:
            prices[AppConsts.CUSTOM_COL_ABZ_MIDDLE] = 0
        if not AppConsts.CUSTOM_COL_ABZ_STD in prices.columns:
            prices[AppConsts.CUSTOM_COL_ABZ_STD] = 0
        if not AppConsts.CUSTOM_COL_ABZ_UPPER in prices.columns:
            prices[AppConsts.CUSTOM_COL_ABZ_UPPER] = 0
        if not AppConsts.CUSTOM_COL_ABZ_LOWER in prices.columns:
            prices[AppConsts.CUSTOM_COL_ABZ_LOWER] = 0

        direction: Series = prices.loc[index][target_column].diff(
            abz_er_period).abs()
        volatility: Series = prices.loc[index][target_column].diff().abs(
        ).rolling(abz_er_period).sum()
        er: Series = direction / volatility
        periods: Series = er * abz_constant_k
        prices[AppConsts.CUSTOM_COL_ABZ_PERIOD].update(periods)

        cursor: int = 0
        for i, row in prices.loc[index].iterrows():
            symbol_id: int = i[0]
            curr_date: date = i[1]
            period: int = NumberUtils.to_int(
                row[AppConsts.CUSTOM_COL_ABZ_PERIOD])
            period = period if period > 2 else 2
            sma_series: Series = prices.loc[index][target_column].rolling(
                period).mean()
            std_series: Series = prices.loc[index][target_column].rolling(
                period).std()
            sma: float = sma_series[symbol_id, curr_date]
            std: float = std_series[symbol_id, curr_date]
            upper: float = sma + (std * abz_std_distance)
            lower: float = sma - (std * abz_std_distance)
            prices[AppConsts.CUSTOM_COL_ABZ_MIDDLE].loc[symbol_id,
                                                        curr_date] = sma
            prices[AppConsts.CUSTOM_COL_ABZ_UPPER].loc[symbol_id,
                                                       curr_date] = upper
            prices[AppConsts.CUSTOM_COL_ABZ_LOWER].loc[symbol_id,
                                                       curr_date] = lower
            cursor += 1

        return prices
Beispiel #10
0
    def append_exponential_smoothing_max_min(
            self, prices: DataFrame, index: Any,
            exponential_smoothing_max_min_diff: float) -> DataFrame:

        if not (isinstance(prices, DataFrame)
                and AppConsts.PRICE_COL_SYMBOL_ID in prices.index.names
                and AppConsts.PRICE_COL_DATE in prices.index.names
                and AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_PRICE
                in prices.columns
                and AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_PRICE_PREV
                in prices.columns
                and AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_PRICE_NEXT
                in prices.columns):
            return None
        if not AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_MAX in prices.columns:
            prices[AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_MAX] = 0
        if not AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_MIN in prices.columns:
            prices[AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_MIN] = 0

        curr_exp_smoothed_maxmin: float = 0.1
        for i, row in prices.loc[index].iterrows():
            symbol_id: int = i[0]
            curr_date: date = i[1]
            curr_exp_smoothed_p: float = row[
                AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_PRICE]
            prev_exp_smoothed_p: float = row[
                AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_PRICE_PREV]
            next_exp_smoothed_p: float = row[
                AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_PRICE_NEXT]
            maxmin_diff: float = NumberUtils.get_change(
                curr_exp_smoothed_p, curr_exp_smoothed_maxmin)
            is_max: bool = (
                not np.isnan(prev_exp_smoothed_p)
                and not prev_exp_smoothed_p == 0
                and not np.isnan(next_exp_smoothed_p)
                and not next_exp_smoothed_p == 0 and maxmin_diff is not None
                and curr_exp_smoothed_p > prev_exp_smoothed_p
                and curr_exp_smoothed_p >= next_exp_smoothed_p
                and abs(maxmin_diff) > exponential_smoothing_max_min_diff)
            is_min: bool = (
                not np.isnan(prev_exp_smoothed_p)
                and not prev_exp_smoothed_p == 0
                and not np.isnan(next_exp_smoothed_p)
                and not next_exp_smoothed_p == 0 and maxmin_diff is not None
                and curr_exp_smoothed_p < prev_exp_smoothed_p
                and curr_exp_smoothed_p <= next_exp_smoothed_p
                and abs(maxmin_diff) > exponential_smoothing_max_min_diff)
            prices[AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_MAX].loc[
                symbol_id, curr_date] = 1 if is_max else 0
            prices[AppConsts.CUSTOM_COL_EXPONENTIAL_SMOOTHING_MIN].loc[
                symbol_id, curr_date] = 1 if is_min else 0
            if is_max or is_min:
                curr_exp_smoothed_maxmin = curr_exp_smoothed_p
        return prices
Beispiel #11
0
 def import_from_csv_balancesheets(self) -> str:
     file: str = FileUtils.get_file(AppConsts.BALANCE_SHEET_FILE)
     records: List[Dict] = CsvUtils.parse_as_dict(file)
     for record in records:
         if not self.__is_valid_intrinio_record(record):
             continue
         symbol: str = record.get(AppConsts.INTRINIO_KEY_BLNC_SHEET_TICKER)
         fiscal_period: str = record.get(
             AppConsts.INTRINIO_KEY_BLNC_SHEET_FISC_PD)
         year: int = NumberUtils.to_int(
             record.get(AppConsts.INTRINIO_KEY_BLNC_SHEET_FISC_YR))
         quarter: int = self.__get_quarter(fiscal_period)
         org_symbol: SM = self.__stock_service.get_symbol(
             symbol, AppConsts.INSTRUMENT_STOCK)
         if not org_symbol:
             continue
         org_fn: FN = self.__stock_service.get_financial(
             org_symbol.id, year, quarter)
         if not org_fn:
             continue
         org_fn.current_assets = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_BLNC_SHEET_CURR_ASSETS))
         org_fn.ttl_assets = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_BLNC_SHEET_ASSETS))
         org_fn.current_liabilities = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_BLNC_SHEET_CURR_LIABS))
         org_fn.ttl_liabilities = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_BLNC_SHEET_LIABS))
         org_fn.ttl_equity = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_BLNC_SHEET_EQUITY))
         BaseService._update()
     return "1"
Beispiel #12
0
    def append_double_tops(self, prices: DataFrame, index: Any,
                           price_column: str, smooth_price_column: str,
                           max_column: str, min_column: str,
                           double_tops_diff: float) -> DataFrame:

        if not (isinstance(prices, DataFrame)
                and AppConsts.PRICE_COL_SYMBOL_ID in prices.index.names
                and AppConsts.PRICE_COL_DATE in prices.index.names
                and price_column in prices.columns and smooth_price_column
                in prices.columns and max_column in prices.columns
                and min_column in prices.columns):
            return None
        if not AppConsts.CUSTOM_COL_DOUBLE_TOPS in prices.columns:
            prices[AppConsts.CUSTOM_COL_DOUBLE_TOPS] = 0
        if not AppConsts.CUSTOM_COL_DOUBLE_TOPS_TARGET_PRICE in prices.columns:
            prices[AppConsts.CUSTOM_COL_DOUBLE_TOPS_TARGET_PRICE] = 0
        if not AppConsts.CUSTOM_COL_DOUBLE_TOPS_STOP_LOSS in prices.columns:
            prices[AppConsts.CUSTOM_COL_DOUBLE_TOPS_STOP_LOSS] = 0

        last_four_maxmins: List[float] = []
        for i, row in prices.loc[index].iterrows():
            symbol_id: int = i[0]
            curr_date: date = i[1]
            is_max: bool = row[max_column] == 1
            is_min: bool = row[min_column] == 1
            if is_max or is_min:
                if len(last_four_maxmins) >= 4:
                    last_four_maxmins.pop(0)
                last_four_maxmins.append(row[smooth_price_column])

            if len(last_four_maxmins) < 4:
                continue
            (point_a, point_b, point_c, point_d) = last_four_maxmins
            point_b_d_diff: float = NumberUtils.get_change(point_b, point_d)
            target_price: float = point_c - (point_d - point_c)
            has_double_tops: bool = (point_a < point_b and point_a < point_c
                                     and point_a < point_d
                                     and point_b > point_c
                                     and point_c < point_d
                                     and abs(point_b_d_diff) < double_tops_diff
                                     and row[price_column] < point_c)

            # and row[price_column] > target_price) # Actual Double Tops condition, but get better results without it.
            if has_double_tops:
                prices[AppConsts.CUSTOM_COL_DOUBLE_TOPS].loc[symbol_id,
                                                             curr_date] = 1
                prices[AppConsts.CUSTOM_COL_DOUBLE_TOPS_TARGET_PRICE].loc[
                    symbol_id, curr_date] = target_price
                prices[AppConsts.CUSTOM_COL_DOUBLE_TOPS_STOP_LOSS].loc[
                    symbol_id, curr_date] = point_d

        return prices
Beispiel #13
0
    def import_from_csv_incomestatements(self) -> str:
        BaseService._truncate(FN)

        file: str = FileUtils.get_file(AppConsts.INCOME_STMT_FILE)
        records: List[Dict] = CsvUtils.parse_as_dict(file)
        models: List[Any] = []
        for record in records:
            if not self.__is_valid_intrinio_record(record):
                continue
            symbol: str = record.get(AppConsts.INTRINIO_KEY_INC_STMT_TICKER)
            fiscal_period: str = record.get(
                AppConsts.INTRINIO_KEY_INC_STMT_FISC_PD)
            org_symbol: SM = self.__stock_service.get_symbol(
                symbol, AppConsts.INSTRUMENT_STOCK)
            if not org_symbol:
                continue
            quarter_end_dte: date = DateUtils.get_date(
                record.get(AppConsts.INTRINIO_KEY_INC_STMT_END_DTE),
                AppConsts.INTRINIO_END_DTE_FMT)
            file_date: date = DateUtils.get_date(
                record.get(AppConsts.INTRINIO_KEY_INC_STMT_FILE_DTE),
                AppConsts.INTRINIO_FILE_DTE_FMT)
            models.append(
                (org_symbol.id,
                 record.get(AppConsts.INTRINIO_KEY_INC_STMT_FISC_YR),
                 self.__get_quarter(fiscal_period), quarter_end_dte, file_date,
                 None,
                 NumberUtils.to_float(
                     record.get(AppConsts.INTRINIO_KEY_INC_STMT_TTLREV)),
                 NumberUtils.to_float(
                     record.get(AppConsts.INTRINIO_KEY_INC_STMT_TTLPROF)),
                 NumberUtils.to_float(
                     record.get(AppConsts.INTRINIO_KEY_INC_STMT_TTLOPINC)),
                 NumberUtils.to_float(
                     record.get(AppConsts.INTRINIO_KEY_INC_STMT_NETINC)), None,
                 None, None, None, None, None, None, None, None, None, None,
                 None, None, None, None, None, None, None, None))
        BaseService._insert_bulk(FN, models)
        return "1"
Beispiel #14
0
 def set_readonly_props(self) -> None:
     if not hasattr(self, 'start_date') \
             or not hasattr(self, 'end_date') \
             or not hasattr(self, 'start_price') \
             or not hasattr(self, 'end_price') \
             or not hasattr(self, 'no_of_shares') \
             or not hasattr(self, 'action'):
         return
     delta: timedelta = DateUtils.get_diff(self._end_date, self._start_date)
     if self._action == AppConsts.ACTION_BUY:
         self._net_change_in_price = NumberUtils.round(self._end_price -
                                                       self._start_price)
     elif self._action == AppConsts.ACTION_SELL:
         self._net_change_in_price = NumberUtils.round(self._start_price -
                                                       self._end_price)
     self._year = self._end_date.year
     self._quarter = DateUtils.get_quarter(self._end_date.month)
     self._month = self._end_date.month
     self._hold_length_days = delta.days if delta else 0
     self._change_in_capital = NumberUtils.round(self._net_change_in_price *
                                                 self._no_of_shares)
     self._has_profit = (self._change_in_capital > 0)
Beispiel #15
0
 def get_price_dataframe(self, prices: List[Any]) -> DataFrame:
     if not prices \
             or not isinstance(prices, List) \
             or not isinstance(prices[0], (SPD, EPD)):
         return None
     df: DataFrame = pd.DataFrame(
         data=[
             [
                 p.id,
                 p.symbol_id,  # idx = 0, 0
                 p.price_date,  # idx = 0, 1
                 NumberUtils.to_float(p.open_price),
                 NumberUtils.to_float(p.high_price),
                 NumberUtils.to_float(p.low_price),
                 NumberUtils.to_float(p.close_price),
                 p.volume
             ] for p in prices
         ],
         columns=AppConsts.PRICE_COLS)
     df = df.set_index(
         [AppConsts.PRICE_COL_SYMBOL_ID, AppConsts.PRICE_COL_DATE])
     return df
Beispiel #16
0
 def _has_entry_conditions(self, symbol_id: int,
                           current_date: date) -> bool:
     current_row: Series = self._prices.loc[symbol_id, current_date]
     if NumberUtils.to_float(
             current_row.loc[AppConsts.CUSTOM_COL_SMA_SLOW]) == 0:
         return False
     is_above: bool = (current_row.loc[AppConsts.CUSTOM_COL_SMA_FAST] >
                       current_row.loc[AppConsts.CUSTOM_COL_SMA_SLOW])
     if not symbol_id in self._target:
         self._target[symbol_id] = {}
         self._target[symbol_id]['is_above'] = is_above
         return False
     was_above: bool = self._target[symbol_id]['is_above']
     self._target[symbol_id]['is_above'] = is_above
     return (is_above and not was_above)
Beispiel #17
0
  def test_has_bit_should_return_appropriately(self) -> None:
    # ACT
    zero_has_one: bool = NumberUtils.has_bit(0, 1)
    one_has_one: bool = NumberUtils.has_bit(1, 1)
    one_has_two: bool = NumberUtils.has_bit(1, 2)
    two_has_one: bool = NumberUtils.has_bit(2, 1)
    two_has_two: bool = NumberUtils.has_bit(2, 2)
    two_has_four: bool = NumberUtils.has_bit(2, 4)
    three_has_one: bool = NumberUtils.has_bit(3, 1)
    three_has_two: bool = NumberUtils.has_bit(3, 2)
    three_has_four: bool = NumberUtils.has_bit(3, 4)
    four_has_one: bool = NumberUtils.has_bit(4, 1)
    four_has_two: bool = NumberUtils.has_bit(4, 2)
    four_has_four: bool = NumberUtils.has_bit(4, 4)
    four_has_eight: bool = NumberUtils.has_bit(4, 8)

    # ASSERT
    self.assertFalse(zero_has_one)
    self.assertTrue(one_has_one)
    self.assertFalse(one_has_two)
    self.assertFalse(two_has_one)
    self.assertTrue(two_has_two)
    self.assertFalse(two_has_four)
    self.assertTrue(three_has_one)
    self.assertTrue(three_has_two)
    self.assertFalse(three_has_four)
    self.assertFalse(four_has_one)
    self.assertFalse(four_has_two)
    self.assertTrue(four_has_four)
    self.assertFalse(four_has_eight)
Beispiel #18
0
  def test_delete_bit_should_return_appropriately(self) -> None:
    # ACT
    zero_delete_one: bool = NumberUtils.delete_bit(0, 1)
    zero_delete_two: bool = NumberUtils.delete_bit(0, 2)
    one_delete_one: bool = NumberUtils.delete_bit(1, 1)
    one_delete_two: bool = NumberUtils.delete_bit(1, 2)
    two_delete_one: bool = NumberUtils.delete_bit(2, 1)
    two_delete_two: bool = NumberUtils.delete_bit(2, 2)
    two_delete_four: bool = NumberUtils.delete_bit(2, 4)
    three_delete_one: bool = NumberUtils.delete_bit(3, 1)
    three_delete_two: bool = NumberUtils.delete_bit(3, 2)
    three_delete_four: bool = NumberUtils.delete_bit(3, 4)
    four_delete_one: bool = NumberUtils.delete_bit(4, 1)
    four_delete_two: bool = NumberUtils.delete_bit(4, 2)
    four_delete_four: bool = NumberUtils.delete_bit(4, 4)
    four_delete_eight: bool = NumberUtils.delete_bit(4, 8)

    # ASSERT
    self.assertEqual(0, zero_delete_one)
    self.assertEqual(0, zero_delete_two)
    self.assertEqual(0, one_delete_one)
    self.assertEqual(1, one_delete_two)
    self.assertEqual(2, two_delete_one)
    self.assertEqual(0, two_delete_two)
    self.assertEqual(2, two_delete_four)
    self.assertEqual(2, three_delete_one)
    self.assertEqual(1, three_delete_two)
    self.assertEqual(3, three_delete_four)
    self.assertEqual(4, four_delete_one)
    self.assertEqual(4, four_delete_two)
    self.assertEqual(0, four_delete_four)
    self.assertEqual(4, four_delete_eight)
Beispiel #19
0
 def start_price(self, val: Any) -> None:
     self._start_price = NumberUtils.to_float(val)
Beispiel #20
0
 def end_price(self, val: Any) -> None:
     self._end_price = NumberUtils.to_float(val)
Beispiel #21
0
 def __calc_benchmark_capital(self, req: BackTestRunRequest,
                              start_price: float, end_price: float,
                              no_of_shares: int) -> float:
     capital: float = req.start_capital - (start_price * no_of_shares)
     return NumberUtils.round(capital + (end_price * no_of_shares))
Beispiel #22
0
    def append_inverted_head_and_shoulders(self, prices: DataFrame, index: Any,
                                           price_column: str,
                                           smooth_price_column: str,
                                           max_column: str, min_column: str,
                                           shoulder_diff: float,
                                           neck_diff: float) -> DataFrame:

        if not (isinstance(prices, DataFrame)
                and AppConsts.PRICE_COL_SYMBOL_ID in prices.index.names
                and AppConsts.PRICE_COL_DATE in prices.index.names
                and price_column in prices.columns and smooth_price_column
                in prices.columns and max_column in prices.columns
                and min_column in prices.columns):
            return None
        if not AppConsts.CUSTOM_COL_INVERTED_HEAD_AND_SHOULDERS in prices.columns:
            prices[AppConsts.CUSTOM_COL_INVERTED_HEAD_AND_SHOULDERS] = 0
        if not AppConsts.CUSTOM_COL_INVERTED_HEAD_AND_SHOULDERS_TARGET_PRICE in prices.columns:
            prices[AppConsts.
                   CUSTOM_COL_INVERTED_HEAD_AND_SHOULDERS_TARGET_PRICE] = 0
        if not AppConsts.CUSTOM_COL_INVERTED_HEAD_AND_SHOULDERS_STOP_LOSS in prices.columns:
            prices[
                AppConsts.CUSTOM_COL_INVERTED_HEAD_AND_SHOULDERS_STOP_LOSS] = 0

        last_six_maxmins: List[float] = []
        for i, row in prices.loc[index].iterrows():
            symbol_id: int = i[0]
            curr_date: date = i[1]
            is_max: bool = row[max_column] == 1
            is_min: bool = row[min_column] == 1
            if is_max or is_min:
                if len(last_six_maxmins) >= 6:
                    last_six_maxmins.pop(0)
                last_six_maxmins.append(row[smooth_price_column])

            if len(last_six_maxmins) < 6:
                continue
            (point_a, point_b, point_c, point_d, point_e,
             point_f) = last_six_maxmins
            point_b_f_diff: float = NumberUtils.get_change(point_b, point_f)
            point_c_e_diff: float = NumberUtils.get_change(point_c, point_e)
            neck_point: float = point_c if point_c > point_e else point_e
            target_price: float = neck_point + (neck_point - point_d)
            has_inverted_head_and_shoulders: bool = (
                point_a > point_b and point_a > point_c and point_a > point_d
                and point_a > point_e and point_a > point_f
                and point_b < point_c and point_b > point_d
                and point_b < point_e and point_c > point_d
                and point_c > point_f and point_d < point_e
                and point_d < point_f and abs(point_b_f_diff) < shoulder_diff
                and abs(point_c_e_diff) < neck_point
                and row[price_column] > neck_point
                and row[price_column] < target_price)
            if has_inverted_head_and_shoulders:
                prices[AppConsts.CUSTOM_COL_INVERTED_HEAD_AND_SHOULDERS].loc[
                    symbol_id, curr_date] = 1
                prices[
                    AppConsts.
                    CUSTOM_COL_INVERTED_HEAD_AND_SHOULDERS_TARGET_PRICE].loc[
                        symbol_id, curr_date] = target_price
                prices[AppConsts.
                       CUSTOM_COL_INVERTED_HEAD_AND_SHOULDERS_STOP_LOSS].loc[
                           symbol_id, curr_date] = point_f
        return prices
Beispiel #23
0
    def run(self, req: BackTestRunRequest) -> BackTestRunResponse:
        if not req or not req.is_valid_model():
            raise BadRequestException()
        response: BackTestRunResponse = BackTestRunResponse(req)

        # Init Symbols
        symbols: List[SymbolMaster] = self.__get_symbols__(req)

        # Init Prices
        prices: DataFrame = self.__get_prices__(req, symbols)

        # Do Base Preparation
        prices[AppConsts.CUSTOM_COL_PV] = prices[
            AppConsts.PRICE_COL_CLOSE] * prices[AppConsts.PRICE_COL_VOLUME]
        for s in symbols:
            prices = self.__calc_service.append_sma(
                prices=prices,
                index=[s.id],
                sma_period=AppConsts.ADV_PERIOD_DFLT,
                sma_column_name=AppConsts.CUSTOM_COL_ADV,
                target_column=AppConsts.PRICE_COL_VOLUME)
            prices = self.__calc_service.append_sma(
                prices=prices,
                index=[s.id],
                sma_period=AppConsts.ADPV_PERIOD_DFLT,
                sma_column_name=AppConsts.CUSTOM_COL_ADPV,
                target_column=AppConsts.CUSTOM_COL_PV)

        LogUtils.debug('Prices shape after base preparation={0}'.format(
            prices.shape))

        # region Init Service
        strategy_service: Any = self.__stock_service.get_strategy_service(
            req.strategy_type, req.strategy_request, symbols, prices)
        if not strategy_service or not strategy_service._is_valid_request():
            raise BadRequestException()
        strategy_service._do_preparations()

        LogUtils.debug('Prices shape after strategy preparation={0}'.format(
            prices.shape))
        # endregion

        LogUtils.debug(prices.info())

        # region Init Dates
        start_date: date = DateUtils.add_business_days(req.date_from_obj, -1)
        start_date = DateUtils.add_business_days(start_date, 1)
        start_date_str: str = DateUtils.to_string(start_date)
        end_date: date = DateUtils.add_business_days(req.date_to_obj, -1)
        dates: DataFrame = self.__stock_service.get_dates(
            prices, start_date, end_date)

        LogUtils.debug(
            'Dates actual_start={0}, actual_end={1}, shape={2}'.format(
                start_date, end_date, dates.shape))
        # endregion

        # region Loop Dates
        strategy_item: BackTestResultItem = next(
            b for b in response.back_test_result_items
            if b.target == req.strategy_type)
        strategy_item.capital[start_date_str] = req.start_capital
        strategy_item.capital_available[start_date_str] = req.start_capital
        portfolio: Dict = {}

        for i, date_row in dates.iterrows():
            current_date = date_row[AppConsts.PRICE_COL_DATE]
            current_date_str: str = DateUtils.to_string(current_date)
            next_date = date_row[AppConsts.CUSTOM_COL_NEXT_DATE]
            next_date_str = DateUtils.to_string(next_date)
            next_next_date = date_row[AppConsts.CUSTOM_COL_NEXT_NEXT_DATE]

            shuffle(symbols)
            for symbol in symbols:
                has_price: bool = (symbol.id, current_date) in prices.index
                if not has_price:
                    continue
                price: Series = prices.loc[symbol.id, current_date]

                if symbol.instrument == AppConsts.INSTRUMENT_ETF:

                    # region Benchmark
                    b_result_item: BackTestResultItem = next(
                        b for b in response.back_test_result_items
                        if b.target == symbol.symbol)
                    if not b_result_item:
                        continue

                    if not b_result_item.transactions:
                        no_of_shares: int = self.__stock_service.get_no_of_shares(
                            req.start_capital, req.pct_risk_per_trade,
                            req.volume_limit, price, req.slippage)
                        if no_of_shares == 0:
                            LogUtils.warning('0 shares for ETF={0}'.format(
                                symbol.symbol))
                            continue

                        b_transaction: Transaction = Transaction()
                        b_transaction.symbol_master = symbol
                        b_transaction.action = AppConsts.ACTION_BUY
                        b_transaction.start_date = current_date
                        b_transaction.start_price = price.loc[
                            AppConsts.PRICE_COL_OPEN]
                        b_transaction.no_of_shares = no_of_shares
                        b_result_item.transactions.append(b_transaction)
                        b_result_item.capital[
                            current_date_str] = req.start_capital
                    else:
                        b_transaction: Transaction = b_result_item.transactions[
                            0]
                        b_transaction.end_date = current_date
                        b_transaction.end_price = price.loc[
                            AppConsts.PRICE_COL_CLOSE]
                        b_transaction.set_readonly_props()
                        b_result_item.capital[
                            current_date_str] = self.__calc_benchmark_capital(
                                req, b_transaction.start_price,
                                b_transaction.end_price,
                                b_transaction.no_of_shares)
                    b_result_item.ttl_no_days += 1
                    # endregion

                else:

                    # region Strategy
                    strategy_service._do_calculations(symbol.id, current_date)
                    action: str = strategy_service._get_action()

                    is_in_position: bool = symbol.id in portfolio
                    if not is_in_position:

                        if len(portfolio
                               ) == req.portfolio_max:  # todo: prioritize?
                            continue
                        if current_date == end_date or next_date >= end_date:
                            continue
                        has_next_price: bool = (symbol.id,
                                                next_date) in prices.index
                        has_next_next_price: bool = (
                            symbol.id, next_next_date) in prices.index
                        if not has_next_price or not has_next_next_price:
                            continue
                        adv: float = price.loc[
                            AppConsts.CUSTOM_COL_ADV] if price.loc[
                                AppConsts.CUSTOM_COL_ADV] > 0 else price.loc[
                                    AppConsts.PRICE_COL_VOLUME]
                        if adv < req.adv_min:
                            continue
                        adpv: float = price.loc[
                            AppConsts.CUSTOM_COL_ADPV] if price.loc[
                                AppConsts.CUSTOM_COL_ADPV] > 0 else price.loc[
                                    AppConsts.CUSTOM_COL_PV]
                        if adpv < req.adpv_min:
                            continue

                        next_price: Series = prices.loc[symbol.id, next_date]

                        has_entry_conditions: bool = strategy_service._has_entry_conditions(
                            symbol.id, current_date)
                        if has_entry_conditions:

                            no_of_shares: int = self.__stock_service.get_no_of_shares(
                                strategy_item.
                                capital_available[current_date_str],
                                req.pct_risk_per_trade, req.volume_limit,
                                next_price, req.slippage,
                                action == AppConsts.ACTION_BUY)
                            if no_of_shares == 0:
                                continue

                            trans: Transaction = Transaction()
                            trans.symbol_master = symbol
                            trans.action = action
                            trans.start_date = next_date
                            trans.start_price = next_price.loc[
                                AppConsts.PRICE_COL_OPEN]
                            trans.no_of_shares = no_of_shares

                            trans_amount: float = NumberUtils.round(
                                trans.start_price * no_of_shares)
                            strategy_item.capital_available[
                                current_date_str] -= trans_amount

                            # Add to portfolio
                            portfolio[symbol.id] = trans

                    elif is_in_position:

                        has_exit_conditions: bool = strategy_service._has_exit_conditions(
                            symbol.id, current_date)
                        has_next_next_price: bool = (
                            symbol.id, next_next_date) in prices.index
                        if next_date == end_date or not has_next_next_price or has_exit_conditions:

                            next_price: Series = prices.loc[symbol.id,
                                                            next_date]
                            next_open_price: float = next_price.loc[
                                AppConsts.PRICE_COL_OPEN]
                            slippage_price: float = 0
                            if action == AppConsts.ACTION_BUY:
                                slippage_price: float = NumberUtils.round(
                                    next_open_price -
                                    (next_open_price * AppConsts.BASIS_POINT *
                                     req.slippage))
                            else:
                                slippage_price: float = NumberUtils.round(
                                    next_open_price +
                                    (next_open_price * AppConsts.BASIS_POINT *
                                     req.slippage))
                            trans: Transaction = portfolio.get(symbol.id)
                            trans.end_date = next_date
                            trans.end_price = slippage_price
                            trans.set_readonly_props()
                            strategy_item.transactions.append(trans)

                            if action == AppConsts.ACTION_BUY:
                                trans_amount = NumberUtils.round(
                                    trans.end_price * trans.no_of_shares)
                                strategy_item.capital_available[
                                    current_date_str] += trans_amount
                            else:
                                init_trans_amount = NumberUtils.round(
                                    trans.start_price * trans.no_of_shares)
                                strategy_item.capital_available[
                                    current_date_str] += init_trans_amount
                                strategy_item.capital_available[
                                    current_date_str] += trans.change_in_capital

                            # Remove from portfolio
                            portfolio.pop(symbol.id, None)

                    # endregion

            # capital = capital available + capital in portfolio
            capital: float = strategy_item.capital_available[current_date_str]
            for key, val in portfolio.items():
                price: Series = prices.loc[key, current_date]
                capital += price.loc[
                    AppConsts.PRICE_COL_CLOSE] * val.no_of_shares
            strategy_item.capital[current_date_str] = NumberUtils.round(
                capital)
            strategy_item.ttl_no_days += 1
            strategy_item.capital[next_date_str] = strategy_item.capital[
                current_date_str]
            strategy_item.capital_available[
                next_date_str] = strategy_item.capital_available[
                    current_date_str]

        # endregion

        for result_item in response.back_test_result_items:
            result_item.set_readonly_props()
        return response
Beispiel #24
0
 def import_from_csv_calculations(self) -> str:
     file: str = FileUtils.get_file(AppConsts.FINANCIAL_CALCS_FILE)
     records: List[Dict] = CsvUtils.parse_as_dict(file)
     for record in records:
         if not self.__is_valid_intrinio_record(record):
             continue
         symbol: str = record.get(AppConsts.INTRINIO_KEY_CALCS_TICKER)
         fiscal_period: str = record.get(
             AppConsts.INTRINIO_KEY_CALCS_FISC_PD)
         year: int = NumberUtils.to_int(
             record.get(AppConsts.INTRINIO_KEY_CALCS_FISC_YR))
         quarter: int = self.__get_quarter(fiscal_period)
         org_symbol: SM = self.__stock_service.get_symbol(
             symbol, AppConsts.INSTRUMENT_STOCK)
         if not org_symbol:
             continue
         org_fn: FN = self.__stock_service.get_financial(
             org_symbol.id, year, quarter)
         if not org_fn:
             continue
         org_fn.market_cap = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_MARK_CAP))
         org_fn.revenue_growth = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_REV_GRTH))
         org_fn.revenue_qq_growth = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_REV_QQ_GRTH))
         org_fn.nopat_growth = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_NOPAT_GRTH))
         org_fn.nopat_qq_growth = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_NOTPAT_QQ_GRTH))
         org_fn.net_income_growth = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_INCM_GRTH))
         org_fn.net_income_qq_growth = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_INCM_QQ_GRTH))
         org_fn.free_cash_flow = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_CSH_FLOW))
         org_fn.current_ratio = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_CURR_RATIO))
         org_fn.debt_to_equity_ratio = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_DE_RATIO))
         org_fn.pe_ratio = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_PE_RATIO))
         org_fn.pb_ratio = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_PB_RATIO))
         org_fn.div_payout_ratio = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_DIV_PAYOUT_RATIO))
         org_fn.roe = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_ROE))
         org_fn.roa = NumberUtils.to_float(
             record.get(AppConsts.INTRINIO_KEY_CALCS_ROA))
         BaseService._update()
     return "1"
Beispiel #25
0
    def sync_orders(self) -> int:
        errors: List[Exception] = []
        try:
            req: GetTradeOrdersRequest = GetTradeOrdersRequest()
            req.status = [
                AppConsts.ORDER_STATUS_SUBMITTED_ENTRY,
                AppConsts.ORDER_STATUS_SUBMITTED_EXIT
            ]
            orders: List[TradeOrderCustom] = self.get_trade_orders(req)

            if not orders:
                LogUtils.debug('No orders submitted')

            for order in orders:
                try:
                    LogUtils.debug('Sync order for = {0}'.format(
                        order.symbol_master.symbol))

                    resp: Order = None
                    if order.trade_order.status == AppConsts.ORDER_STATUS_SUBMITTED_ENTRY:
                        resp = self.__alpaca_client.get_order(
                            order.trade_order.alpaca_id)
                    elif order.trade_order.status == AppConsts.ORDER_STATUS_SUBMITTED_EXIT:
                        resp = self.__alpaca_client.get_order(
                            order.trade_order.exit_alpaca_id)

                    if resp:
                        org: TradeOrder = BaseService._get_by_id(
                            TradeOrder, order.trade_order.id)
                        if not org:
                            raise NotFoundException('TradeOrder', 'id',
                                                    order.trade_order.id)

                        if order.trade_order.status == AppConsts.ORDER_STATUS_SUBMITTED_ENTRY \
                                and resp.status == AppConsts.ALPACA_ORDER_STATUS_FILLED:
                            org.status = AppConsts.ORDER_STATUS_IN_POSITION
                            org.actual_qty = NumberUtils.to_int(
                                resp.filled_qty)
                            org.actual_entry_price = NumberUtils.to_float(
                                resp.filled_avg_price)
                            org.modified = datetime.now()
                            BaseService._update()
                        elif order.trade_order.status == AppConsts.ORDER_STATUS_SUBMITTED_ENTRY \
                                and resp.status == AppConsts.ALPACA_ORDER_STATUS_CANCELLED:
                            org.status = AppConsts.ORDER_STATUS_CANCELLED_ENTRY
                            org.modified = datetime.now()
                            BaseService._update()
                        elif order.trade_order.status == AppConsts.ORDER_STATUS_SUBMITTED_EXIT \
                                and resp.status == AppConsts.ALPACA_ORDER_STATUS_FILLED:
                            exit_price: StockPriceDaily = self.__stock_service.get_single_stock_price_daily(
                                order.symbol_master.id,
                                DateUtils.get_date(
                                    datetime.today().strftime('%Y-%m-%d'),
                                    '%Y-%m-%d'))
                            if exit_price:
                                org.exit_stock_price_daily_id = exit_price.id
                            org.status = AppConsts.ORDER_STATUS_COMPLETED
                            org.actual_exit_price = NumberUtils.to_float(
                                resp.filled_avg_price)
                            org.modified = datetime.now()
                            BaseService._update()
                        elif order.trade_order.status == AppConsts.ORDER_STATUS_SUBMITTED_EXIT \
                                and resp.status == AppConsts.ALPACA_ORDER_STATUS_CANCELLED:
                            org.status = AppConsts.ORDER_STATUS_CANCELLED_EXIT
                            org.modified = datetime.now()
                            BaseService._update()
                            raise Exception('Exit Error = {0}'.format(
                                resp.status))
                        else:
                            raise Exception('Sync Status = {0}'.format(
                                resp.status))
                    else:
                        raise NotFoundException('Alpaca Order', 'id',
                                                order.trade_order.alpaca_id)

                except Exception as ex:
                    LogUtils.error('Sync Orders Error', ex)
                    errors.append(ex)

        except Exception as ex:
            LogUtils.error('Sync Orders Error', ex)
            errors.append(ex)
        finally:
            self.__email_client.send_html(
                subject=AppConsts.EMAIL_SUBJECT_SYNC_ORDERS,
                template_path=AppConsts.TEMPLATE_PATH_SYNC_ORDERS,
                model={'errors': errors})
            return 1
Beispiel #26
0
    def queue_positions(self) -> int:
        errors: List[Exception] = []
        try:
            is_tmrw_valid: bool = self.__alpaca_client.is_tmrw_valid()
            if not is_tmrw_valid:
                LogUtils.warning('Tmrw is not a valid trade date')
                raise BadRequestException('Date',
                                          DateUtils.to_string(date.today()))

            req: GetTradeOrdersRequest = GetTradeOrdersRequest()

            # If Sunday, check Friday's price.
            today: date = date.today()
            if today.weekday() == AppConsts.WEEKDAY_IDX_SUN:
                today = DateUtils.add_business_days(today, -1)
            req.created = today.strftime('%Y-%m-%d')

            req.exact_status = AppConsts.ORDER_STATUS_INIT
            orders: List[TradeOrderCustom] = self.get_trade_orders(req)

            req_to_ignore: GetTradeOrdersRequest = GetTradeOrdersRequest()
            req_to_ignore.status = [
                AppConsts.ORDER_STATUS_SUBMITTED_ENTRY,
                AppConsts.ORDER_STATUS_IN_POSITION,
                AppConsts.ORDER_STATUS_SUBMITTED_EXIT,
                AppConsts.ORDER_STATUS_CANCELLED_EXIT
            ]
            orders_to_ignore: List[TradeOrderCustom] = self.get_trade_orders(
                req_to_ignore)
            symbols_to_ignore: List[str] = [
                o.symbol_master.symbol for o in orders_to_ignore
            ] if orders_to_ignore else []

            LogUtils.debug('symbols_to_ignore = {0}'.format(symbols_to_ignore))

            if not orders:
                LogUtils.debug('No orders suggested')

            shuffle(orders)
            prioritized_orders: List[TradeOrderCustom] = []
            for order in orders:
                if order.trade_order.strategy == AppConsts.STRATEGY_DOUBLE_BOTTOMS:
                    prioritized_orders.append(order)
            for order in orders:
                if order.trade_order.strategy == AppConsts.STRATEGY_DOUBLE_TOPS:
                    prioritized_orders.append(order)

            accnt: Account = self.__alpaca_client.get_account()
            capital: float = NumberUtils.to_floor(
                NumberUtils.to_float(accnt._raw['buying_power']) /
                2)  # 2 to trade everyday
            for order in prioritized_orders:
                try:
                    LogUtils.debug('Try symbol = {0}'.format(
                        order.symbol_master.symbol))

                    if order.symbol_master.symbol in symbols_to_ignore:
                        LogUtils.debug('Ignore for = {0}'.format(
                            order.symbol_master.symbol))
                        continue

                    cost: float = NumberUtils.to_float(
                        order.stock_price_daily.close_price *
                        order.trade_order.qty)

                    if cost > capital:
                        LogUtils.debug('Too expensive for = {0}'.format(
                            order.symbol_master.symbol))
                        continue
                    capital = capital - cost

                    resp: Order = self.__alpaca_client.submit_order(
                        symbol=order.symbol_master.symbol,
                        qty=order.trade_order.qty,
                        action=order.trade_order.action)
                    if resp:
                        org: TradeOrder = BaseService._get_by_id(
                            TradeOrder, order.trade_order.id)
                        if not org:
                            raise NotFoundException('TradeOrder', 'id',
                                                    order.trade_order.id)
                        org.alpaca_id = resp.id
                        org.status = AppConsts.ORDER_STATUS_SUBMITTED_ENTRY
                        org.order_type = AppConsts.ORDER_TYPE_MARKET
                        org.time_in_force = AppConsts.TIME_IN_FORCE_DAY
                        org.modified = datetime.now()
                        BaseService._update()

                except Exception as ex:
                    LogUtils.error('Queue Position Error', ex)
                    errors.append(ex)

        except Exception as ex:
            LogUtils.error('Queue Position Error', ex)
            errors.append(ex)
        finally:
            self.__email_client.send_html(
                subject=AppConsts.EMAIL_SUBJECT_QUEUE_POSITIONS,
                template_path=AppConsts.TEMPLATE_PATH_QUEUE_POSITIONS,
                model={'errors': errors})
            return 1
Beispiel #27
0
  def test_add_bit_should_return_appropriately(self) -> None:
    # ACT
    zero_add_one: bool = NumberUtils.add_bit(0, 1)
    zero_add_two: bool = NumberUtils.add_bit(0, 2)
    one_add_one: bool = NumberUtils.add_bit(1, 1)
    one_add_two: bool = NumberUtils.add_bit(1, 2)
    two_add_one: bool = NumberUtils.add_bit(2, 1)
    two_add_two: bool = NumberUtils.add_bit(2, 2)
    two_add_four: bool = NumberUtils.add_bit(2, 4)
    three_add_one: bool = NumberUtils.add_bit(3, 1)
    three_add_two: bool = NumberUtils.add_bit(3, 2)
    three_add_four: bool = NumberUtils.add_bit(3, 4)
    four_add_one: bool = NumberUtils.add_bit(4, 1)
    four_add_two: bool = NumberUtils.add_bit(4, 2)
    four_add_four: bool = NumberUtils.add_bit(4, 4)
    four_add_eight: bool = NumberUtils.add_bit(4, 8)

    # ASSERT
    self.assertEqual(1, zero_add_one)
    self.assertEqual(2, zero_add_two)
    self.assertEqual(1, one_add_one)
    self.assertEqual(3, one_add_two)
    self.assertEqual(3, two_add_one)
    self.assertEqual(2, two_add_two)
    self.assertEqual(6, two_add_four)
    self.assertEqual(3, three_add_one)
    self.assertEqual(3, three_add_two)
    self.assertEqual(7, three_add_four)
    self.assertEqual(5, four_add_one)
    self.assertEqual(6, four_add_two)
    self.assertEqual(4, four_add_four)
    self.assertEqual(12, four_add_eight)