Beispiel #1
0
 def setUp(self):
     print('api_key: ', end="")
     api_key = ''
     print('api_secret: ', end="")
     api_secret = ''
     self.api_gateway = ApiGateway(api_key=api_key, api_secret=api_secret)
     self.order_id = None
    def __init__(self, pair='xrp_jpy', candle_type='15min', buying_price=None, limit=None, init_max_high=None, init_min_low=None):
        self.__pair = pair
        self.__candle_type = candle_type
        self.__api_gateway = ApiGateway()
        self.rsi_data = None
        self.rsi_step = None
        self.max_high = None
        self.min_low = None
        self.price = None
        self.trend = None
        # 設定
        self.buy_deviation = 0.03
        self.sell_deviation = 0.02
        self.rsi_term = 14
        self.rsi_bottom = 40.0
        self.rsi_top = 60.0

        self.__line = Line()
        self.buying_price = buying_price
        self.limit = limit
        self.decision_term = 0
        self.candlestick = self.make_price_data_frame()
        self.init_max_high = init_max_high
        self.init_min_low = init_min_low
        self()
Beispiel #3
0
 def __init__(self,
              short_term=12,
              long_term=26,
              signal=9,
              pair='xrp_jpy',
              candle_type='5min'):
     self.__short_term = short_term
     self.__long_term = long_term
     self.__signal = signal
     self.__pair = pair
     self.__candle_type = candle_type
     self.__api_gateway = ApiGateway()
     self.df_signal = None
     self.make_data_frame()
     self.trend_15min = None
     self.trend_5min = None
     self.area_15min = list()
     self.area_5min = list()
     self.max_histogram_5min = 0
     self.max_histogram_15min = 0
     self.start_macd_15min = None
     self.start_macd_5min = None
     self.start_signal_15min = None
     self.start_signal_5min = None
     self.mount_15min = None
     self.mount_5min = None
     self.count_15min = 1
     self.count_5min = 1
     self.is_plus_start_15min = None
     self.is_plus_start_5min = None
     self.max_price = None
     self.recognize()
Beispiel #4
0
class Adviser(ABC):
    BUY = 1
    STAY = 2
    SELL = 3
    RETRY = 4

    BUY_TYPE = 'buy'
    SELL_TYPE = 'sell'

    DEFAULT_TYPE = 'market'
    TYPE_LIMIT = 'limit'
    TYPE_MARKET = 'market'

    def __init__(self, pair='xrp_jpy', candle_type='15min', buying_price=None):
        self.api_gateway = ApiGateway()
        self.pair = pair
        self.candle_type = candle_type
        self.buying_price = buying_price
        self.candlestick = self.make_price_data_frame()

    @abstractmethod
    def operation(self, has_coin, is_waiting, buying_price, waiting_price, price=None):
        """
        指示と取引価格を渡す。
        :param has_coin: bool
        :param price: None|float
        :param is_waiting: bool
        :param buying_price: float|None
        :param waiting_price:
        :return: const int, float
        """
        pass

    def make_price_data_frame(self):
        """
        直近のロウソク足データ(2日分)から終値のデータフレームを作る
        :return: pandas.DataFrame 2日分のロウソク足データ
        """
        today = datetime.datetime.now(timezone('UTC'))
        yesterday = today - datetime.timedelta(days=1)
        today = today.astimezone(timezone('Asia/Tokyo'))
        yesterday = yesterday.astimezone(timezone('Asia/Tokyo'))
        candlestick_today = self.api_gateway.use_candlestick(
            time=today.strftime("%Y%m%d"),
            candle_type=self.candle_type,
            pair=self.pair
        )['candlestick'][0]['ohlcv']
        candlestick_yesterday = self.api_gateway.use_candlestick(
            time=yesterday.strftime('%Y%m%d'),
            candle_type=self.candle_type,
            pair=self.pair
        )['candlestick'][0]['ohlcv']
        for item in candlestick_today:
            candlestick_yesterday.append(item)
        loc = datetime.datetime.fromtimestamp(int(candlestick_yesterday[-1][5]) / 1000)
        print('last: ', loc)
        return pd.DataFrame(candlestick_yesterday, columns=['open', 'high', 'low', 'end', 'yield', 'time'])
Beispiel #5
0
 def __init__(self, adviser, pair, log):
     """
     :param adviser:       bitbank.adviser テクニカル分析結果から売却の指示をするクラスのインスタンス
     :param pair:          string          通貨のペア
     :param log:
     """
     super().__init__(adviser=adviser, pair=pair)
     self.order_id = 0
     self.has_coin = False
     self.is_waiting = False
     self.waiting_price = None
     self.log = log
     self.api_gateway = ApiGateway()
 def __init__(self, adviser, pair, api_key=None, api_secret=None):
     """
     :param adviser:       bitbank.adviser テクニカル分析結果から売却の指示をするクラスのインスタンス
     :param pair:          string          通貨のペア
     :param api_key:
     :param api_secret:
     """
     self.adviser = adviser
     self.pair = pair
     self.coin = pair.split('_')[0]
     self.yen = pair.split('_')[1]
     self.api_gateway = ApiGateway(api_key=api_key, api_secret=api_secret)
     self.buying_price = None
     self.order_ids = None
     self.__line = Line()
     self.__start_price = self.fetch_price()
 def __init__(self,
              stock_term,
              inclination_alpha,
              pair,
              candle_type='5min'):
     self.__recent_data = None
     self.__recent_sma = None
     self.__recent_sigma = None
     self.__volatility = None
     self.__last_location = None
     self.__pre_location = None
     self.__inclination_pattern = None
     self.__stock_term = stock_term
     self.__inclination_alpha = inclination_alpha
     self.__pair = pair
     self.__candle_type = candle_type
     self.__api_gateway = ApiGateway()
     self.__initialize()
Beispiel #8
0
 def __init__(self, pair='xrp_jpy', candle_type='15min', buying_price=None):
     self.api_gateway = ApiGateway()
     self.pair = pair
     self.candle_type = candle_type
     self.buying_price = buying_price
     self.candlestick = self.make_price_data_frame()
Beispiel #9
0
class Prototype(Auto):
    DIVIDE_ORDER = 1
    PRICE_LIMIT = 3.0

    COMMISSION = 0.0015
    LOSS_CUT_PRICE = 0.5

    BUY_FAIL = 0.02
    SELL_FAIL = 0.02

    def __init__(self, adviser, pair, log):
        """
        :param adviser:       bitbank.adviser テクニカル分析結果から売却の指示をするクラスのインスタンス
        :param pair:          string          通貨のペア
        :param log:
        """
        super().__init__(adviser=adviser, pair=pair)
        self.order_id = 0
        self.has_coin = False
        self.is_waiting = False
        self.waiting_price = None
        self.log = log
        self.api_gateway = ApiGateway()

    def __call__(self):
        # 要求を確認
        self.check_request()
        # 指示を受ける
        operation, price, order_type = self.adviser.operation(
            has_coin=self.has_coin,
            is_waiting=self.is_waiting,
            buying_price=self.buying_price,
            waiting_price=self.waiting_price)
        self.request(operation=operation, price=price, order_type=order_type)

    def request(self, operation, price, order_type):
        if operation == int(self.BUY):
            line_ = 'BUY         : {:<10}'.format(price) + now() + '\n'
            over_write_file(directory=self.log, line_=line_)
            self.buy(price=price, amount='hoge', order_type=order_type)

        elif operation == int(self.SELL):
            line_ = 'SELL        : {:<10}'.format(price) + now() + '\n'
            over_write_file(directory=self.log, line_=line_)
            self.sell(price=price, amount='hoge', order_type=order_type)

        elif operation == int(self.RETRY):
            # キャンセル
            result = self.cancel_orders(order_id=self.order_id)
            # 再要求
            if result.side == 'buy':
                line_ = 'RETRY BUY  : {:<10}'.format(price) + now() + '\n'
                over_write_file(directory=self.log, line_=line_)
                self.buy(price=price,
                         amount=result.remaining_amount,
                         order_type=order_type)
            elif result.side == 'sell':
                line_ = 'RETRY SELL : {:<10}'.format(price) + now() + '\n'
                over_write_file(directory=self.log, line_=line_)
                self.sell(price=price,
                          amount=result.remaining_amount,
                          order_type=order_type)
        elif operation == int(self.STAY):
            pass
        else:
            raise SchedulerCancelException('operation fail')

    def check_request(self):
        if self.is_waiting:
            price = float(self.api_gateway.use_ticker(pair=self.pair)['last'])
            # 売り
            if self.has_coin:
                if self.waiting_price <= price:
                    self.waiting_price = None
                    self.is_waiting = False
                    self.contract_order_message()
            # 買い
            else:
                if self.waiting_price >= price:
                    self.waiting_price = None
                    self.is_waiting = False
                    self.contract_order_message()

    def buy(self, price, amount, order_type):
        self.new_orders(price=price,
                        amount=amount,
                        side='buy',
                        order_type=order_type)
        self.buying_price = price
        self.has_coin = True

    def sell(self, price, amount, order_type):
        self.new_orders(price=price,
                        amount=amount,
                        side='sell',
                        order_type=order_type)
        self.buying_price = None
        self.has_coin = False

    def new_orders(self, price, amount, side, order_type, retry=0):
        """
        新規注文を行う
        :param price:      number
        :param amount:     number
        :param side:       string
        :param order_type: string
        :param retry:      integer
        """
        try:
            # Orderインスタンス化
            order = Order(order_id=0,
                          pair=self.pair,
                          side=side,
                          type=order_type,
                          price=price,
                          start_amount=amount,
                          remaining_amount=0,
                          executed_amount=0,
                          average_price=0,
                          ordered_at=now(),
                          status='')

            self.new_order_message(order=order, retry=retry)
            self.order_id += 1
            self.waiting_price = price
            self.is_waiting = True
            print()
            print(order.ordered_at + '   ' + side + ' ' + order.start_amount +
                  ' ' + str(order.price))
        except Exception as e:
            print(e)
            self.error_message(message=e.args[0])
            raise SchedulerCancelException('Fail to order')

    def cancel_orders(self, order_id):
        """
        現在の注文をキャンセルする
        :param order_id:  number
        """
        try:
            # 強制的にsideを決める
            result = {
                'order_id': order_id,
                'side': self.__side(),
                'status': 'hoge',
                'pair': 'hoge',
                'price': 'hoge',
                'average_price': 'hoge',
                'start_amount': 'hoge',
                'executed_amount': 'hoge',
                'remaining_amount': 'hoge',
                'ordered_at': 'hoge',
                'type': 'hoge'
            }
            self.cancel_order_message(result=result)
            self.order_id -= 1
            self.waiting_price = None
            self.is_waiting = False
            order = Order.order(r=result)
            return order
        except Exception as e:
            print(e)
            raise SchedulerCancelException('Fail to cancel order')

    def __side(self):
        if self.has_coin:
            return 'sell'
        elif self.has_coin:
            return 'buy'
class ZigZagAdviser:
    BUY = 1
    STAY = 2
    SELL = 3

    TOP = 10   # 値幅率を超えて上がっているときの状態
    BOTTOM = 11   # 値幅率を超えて下がっているときの状態
    OTHER = 12

    TOP_DECISION_TERM = 60   #
    BOTTOM_DECISION_TERM = 400   #

    FETCH_TERM = 4  # 4 /min
    CANDLESTICK = 15  # 15min

    def __init__(self, pair='xrp_jpy', candle_type='15min', buying_price=None, limit=None, init_max_high=None, init_min_low=None):
        self.__pair = pair
        self.__candle_type = candle_type
        self.__api_gateway = ApiGateway()
        self.rsi_data = None
        self.rsi_step = None
        self.max_high = None
        self.min_low = None
        self.price = None
        self.trend = None
        # 設定
        self.buy_deviation = 0.03
        self.sell_deviation = 0.02
        self.rsi_term = 14
        self.rsi_bottom = 40.0
        self.rsi_top = 60.0

        self.__line = Line()
        self.buying_price = buying_price
        self.limit = limit
        self.decision_term = 0
        self.candlestick = self.make_price_data_frame()
        self.init_max_high = init_max_high
        self.init_min_low = init_min_low
        self()

    def __call__(self):
        self.is_candlestick = True
        self.zigzag_candlestick()
        self.is_candlestick = False
        self.candlestick = None
        # 初期値
        if self.init_max_high is not None:
            self.max_high = self.init_max_high
        if self.init_min_low is not None:
            self.min_low = self.init_min_low

    def operation(self, has_coin):
        # 売りのエントリー
        if self.trend == self.TOP and has_coin:
            operation = self.SELL
            return operation, self.price

        # 買いのエントリー
        elif self.trend == self.BOTTOM and not has_coin:
            operation = self.BUY
            self.buying_price = self.price
            return operation, self.price

        elif self.trend == self.OTHER:
            operation = self.STAY
            return operation, self.price
        else:
            operation = self.STAY
            return operation, self.price

    def fetch_recent_data(self, price=None):
        """
        現在のtickerのapiを叩いて、最新の取引値を追加してデータを更新する
        """
        if price is None:
            price = self.__api_gateway.use_ticker(pair=self.__pair)
            price = float(price['last'])

        self.__update_min_max(high=price, low=price)
        self.price = price
        # RSI
        self.__fetch_rsi()

        self.__trend()

    def __fetch_rsi(self):
        self.rsi_step += 1
        # 新たな区間を追加
        if self.rsi_step == self.FETCH_TERM * self.CANDLESTICK:
            self.rsi_step = 0
            del self.rsi_data[0]
            self.rsi_data.append({
                'start': self.price,
                'end': self.price,
            })
        # 最後の区間を更新
        else:
            self.rsi_data[-1]['end'] = self.price

    def zigzag_candlestick(self):
        self.max_high = float(self.candlestick.loc[0].high)
        self.min_low = float(self.candlestick.loc[0].low)

        for data_i in range(1, len(self.candlestick)):
            high = float(self.candlestick.loc[data_i].high)
            low = float(self.candlestick.loc[data_i].low)

            self.__update_min_max(high=high, low=low)

            self.__trend(high=high, low=low)

        # RSI
        self.rsi_data = list()
        for data_i in range(len(self.candlestick) - self.rsi_term, len(self.candlestick)):
            self.rsi_data.append({
                'start': float(self.candlestick.loc[data_i].open),
                'end': float(self.candlestick.loc[data_i].end)
            })
        self.rsi_step = 0

    def rsi(self):
        plus = list()
        minus = list()
        for data in self.rsi_data:
            diff = data['end'] - data['start']
            if diff > 0:
                plus.append(diff)
            else:
                minus.append(-1 * diff)
        if len(plus) > 0:
            plus_sum = sum(plus)
        else:
            plus_sum = 0
        if len(minus) > 0:
            minus_sum = sum(minus)
        else:
            minus_sum = 0
        return plus_sum / (plus_sum + minus_sum) * 100

    def __update_min_max(self, high, low):
        if self.max_high < high:
            self.max_high = high
        if self.min_low > low:
            self.min_low = low

    def __top(self):
        """
        値幅率を超えて上がったときにTrue
        :return:
        """
        if self.price is None:
            price = self.max_high
        else:
            price = self.price
        if self.buying_price is None or self.is_candlestick:
            return self.__and_gate(
                self.min_low * (1 + self.sell_deviation) < price,
            )
        else:
            return self.__and_gate(
                self.min_low * (1 + self.sell_deviation) < price,
                self.buying_price <= self.price
            )

    def __bottom(self):
        """
        値幅率を超えて下がったときにTrue
        :return:
        """
        if self.price is None:
            price = self.min_low
        else:
            price = self.price
        if self.limit is None or self.is_candlestick:
            return self.__and_gate(
                self.max_high * (1 - self.buy_deviation) > price,
            )
        else:
            return self.__and_gate(
                self.max_high * (1 - self.buy_deviation) > price,
                self.limit >= self.price
            )

    def __trend(self, high=None, low=None):
        if high is None:
            high = self.price
        if low is None:
            low = self.price

        self.trend = self.OTHER

        if not self.is_candlestick:
            print(self.min_low, self.price, self.max_high)

        if self.__top():
            # 最大値更新
            if high >= self.max_high:
                self.decision_term = 0
                if not self.is_candlestick:
                    self.__line(message="最大値を更新")
            else:
                self.decision_term += 1
                if not self.is_candlestick:
                    rsi = self.rsi()
                    self.__deliberating_message(side='sell', rsi=rsi)
                else:
                    rsi = True
                # 山を決定
                if self.is_candlestick or (self.decision_term >= self.TOP_DECISION_TERM and self.rsi_top <= rsi):
                    self.decision_term = 0
                    self.trend = self.TOP
                    self.min_low = low
                    print('TOP')

        elif self.__bottom():
            # 最小値更新
            if low <= self.min_low:
                self.decision_term = 0
                if not self.is_candlestick:
                    self.__line(message="最小値を更新")
            else:
                self.decision_term += 1
                # 谷を決定
                if not self.is_candlestick:
                    rsi = self.rsi()
                    self.__deliberating_message(side='buy', rsi=rsi)
                else:
                    rsi = True
                if self.is_candlestick or (self.decision_term >= self.BOTTOM_DECISION_TERM and self.rsi_bottom >= rsi):
                    self.decision_term = 0
                    self.trend = self.BOTTOM
                    self.max_high = high
                    print('BOTTOM')
        else:
            self.decision_term = 0

    def __deliberating_message(self, side, **kwargs):
        if side == 'buy':
            message = "買いエントリーを審議中\n" \
                      "decision : " + str(self.decision_term) + "\n" \
                      "RSI : " + str(kwargs['rsi']) + "\n" \
                      "" + str(now())
        elif side == 'sell':
            message = "売りエントリーを審議中\n" \
                      "decision : " + str(self.decision_term) + "\n" \
                      "RSI : " + str(kwargs['rsi']) + "\n" \
                      "" + str(now())
        else:
            message = ""
        if self.decision_term == 1 or self.decision_term % 10 == 0:
            self.__line(message=message)

    @staticmethod
    def __and_gate(*args):
        return all(args)

    def make_price_data_frame(self):
        """
        直近のロウソク足データ(2日分)から終値のデータフレームを作る
        :return: pandas.DataFrame 2日分のロウソク足データ
        """
        today = datetime.datetime.now(timezone('UTC'))
        yesterday = today - datetime.timedelta(days=1)
        today = today.astimezone(timezone('Asia/Tokyo'))
        yesterday = yesterday.astimezone(timezone('Asia/Tokyo'))
        print('Initializing Candlestick Data From',
              today.strftime('%Y-%m-%d'),
              'and',
              yesterday.strftime('%Y-%m-%d')
              )
        candlestick_today = self.__api_gateway.use_candlestick(
            time=today.strftime("%Y%m%d"),
            candle_type=self.__candle_type,
            pair=self.__pair
        )['candlestick'][0]['ohlcv']
        candlestick_yesterday = self.__api_gateway.use_candlestick(
            time=yesterday.strftime('%Y%m%d'),
            candle_type=self.__candle_type,
            pair=self.__pair
        )['candlestick'][0]['ohlcv']
        for item in candlestick_today:
            candlestick_yesterday.append(item)
        return pd.DataFrame(candlestick_yesterday, columns=['open', 'high', 'low', 'end', 'yield', 'time'])
Beispiel #11
0
class MACDAdviser:
    MINUS = -1
    PLUS = 1

    BUY = 1
    STAY = 2
    SELL = 3

    def __init__(self,
                 short_term=12,
                 long_term=26,
                 signal=9,
                 pair='xrp_jpy',
                 candle_type='5min'):
        self.__short_term = short_term
        self.__long_term = long_term
        self.__signal = signal
        self.__pair = pair
        self.__candle_type = candle_type
        self.__api_gateway = ApiGateway()
        self.df_signal = None
        self.make_data_frame()
        self.trend_15min = None
        self.trend_5min = None
        self.area_15min = list()
        self.area_5min = list()
        self.max_histogram_5min = 0
        self.max_histogram_15min = 0
        self.start_macd_15min = None
        self.start_macd_5min = None
        self.start_signal_15min = None
        self.start_signal_5min = None
        self.mount_15min = None
        self.mount_5min = None
        self.count_15min = 1
        self.count_5min = 1
        self.is_plus_start_15min = None
        self.is_plus_start_5min = None
        self.max_price = None
        self.recognize()

    def operation(self, genome, has_coin):
        """
        :return: const integer, float
        """
        # price_rate = genome[28]
        price_rate = 0.9
        histogram_15min = float(self.df_signal.tail(1).histogram_15min)
        histogram_5min = float(self.df_signal.tail(1).histogram_5min)
        histogram_1min = float(self.df_signal.tail(1).histogram_1min)
        pre_trend_15min = self.trend_15min
        pre_trend_5min = self.trend_5min
        macd_15min = float(self.df_signal.tail(1).macd_15min)
        macd_5min = float(self.df_signal.tail(1).macd_5min)
        macd_1min = float(self.df_signal.tail(1).macd_1min)
        signal_15min = float(self.df_signal.tail(1).signal_15min)
        signal_5min = float(self.df_signal.tail(1).signal_5min)
        signal_1min = float(self.df_signal.tail(1).signal_1min)
        price = float(self.df_signal.tail(1).price)

        self.__check_trend(histogram_15min=histogram_15min,
                           histogram_5min=histogram_1min)
        check_5min = self.__check_5min()

        if check_5min:
            if pre_trend_15min == self.trend_15min:
                self.area_15min.append(histogram_15min)
                if abs(self.max_histogram_15min) < abs(histogram_15min):
                    self.max_histogram_15min = histogram_15min
            else:
                self.area_15min = list()
                self.area_15min.append(histogram_15min)
                self.max_histogram_15min = histogram_15min
                self.start_macd_15min = macd_15min
                self.start_signal_15min = signal_15min
                if has_coin is False and signal_15min > 0:
                    self.is_plus_start_15min = True
                else:
                    self.is_plus_start_15min = False

            if pre_trend_5min == self.trend_5min:
                self.area_5min.append(histogram_1min)
                if abs(self.max_histogram_5min) < abs(histogram_1min):
                    self.max_histogram_5min = histogram_1min
            else:
                self.area_5min = list()
                self.area_5min.append(histogram_1min)
                self.max_histogram_5min = histogram_1min
                self.start_macd_5min = macd_1min
                self.start_signal_5min = signal_1min
                if has_coin is False and signal_1min > 0:
                    self.is_plus_start_5min = True
                else:
                    self.is_plus_start_5min = False
        else:
            if pre_trend_5min == self.trend_5min:
                self.area_5min[-1] = histogram_1min
                if abs(self.max_histogram_5min) < abs(histogram_1min):
                    self.max_histogram_5min = histogram_1min
            else:
                self.area_5min = list()
                self.area_5min.append(histogram_1min)
                self.max_histogram_5min = histogram_1min
                self.start_macd_5min = macd_1min
                self.start_signal_5min = signal_1min
                if has_coin is False and signal_1min > 0:
                    self.is_plus_start_5min = True
                else:
                    self.is_plus_start_5min = False

        # 山が下がり始めたら
        if len(self.area_5min) > 1 and abs(
                self.area_5min[-1]) > abs(histogram_1min):
            step_size_5min = len(self.area_5min)
            start_decrease_5min = True
        else:
            step_size_5min = None
            start_decrease_5min = False
        if len(self.area_15min) > 1 and abs(self.area_15min[-1]) < abs(
                self.area_15min[-2]):
            step_size_15min = len(self.area_15min)
            start_decrease_15min = True
        else:
            step_size_15min = None
            start_decrease_15min = False

        if start_decrease_5min and start_decrease_15min:

            if not has_coin and self.is_plus_start_15min and self.is_plus_start_5min:
                decrease_rate_15min = genome[0]
                step_rate_15min = genome[1]
                decrease_rate_5min = genome[2]
                step_rate_5min = genome[3]
                start_macd_15min = genome[4]
                start_signal_15min = genome[5]
                start_macd_5min = genome[6]
                start_signal_5min = genome[7]
                end_macd_15min = genome[8]
                end_signal_15min = genome[9]
                end_macd_5min = genome[10]
                end_signal_5min = genome[11]

                # MAX条件
                max_threshold_5min = step_rate_5min * step_size_5min * self.max_histogram_5min
                max_threshold_5min += start_macd_5min * self.start_macd_5min
                max_threshold_5min += start_signal_5min * self.start_signal_5min
                max_threshold_5min += end_macd_5min * macd_5min
                max_threshold_5min += end_signal_5min * signal_5min
                max_threshold_15min = step_rate_15min * step_size_5min * self.max_histogram_15min
                max_threshold_15min += start_macd_15min * self.start_macd_15min
                max_threshold_15min += start_signal_15min * self.start_signal_15min
                max_threshold_15min += end_macd_15min * macd_15min
                max_threshold_15min += end_signal_15min * signal_15min
                # 降下条件
                decrease_threshold_5min = self.max_histogram_5min * decrease_rate_5min
                decrease_threshold_15min = self.max_histogram_15min * decrease_rate_15min

                buy = self.and_gate(
                    self.max_histogram_15min < max_threshold_15min,
                    decrease_threshold_15min < histogram_15min,
                    self.max_histogram_5min < max_threshold_5min,
                    decrease_threshold_5min < histogram_1min,
                )
                if buy:
                    operation = self.BUY
                else:
                    operation = self.STAY

            elif has_coin:
                decrease_rate_15min = genome[12]
                step_rate_15min = genome[13]
                decrease_rate_5min = genome[14]
                step_rate_5min = genome[15]
                start_macd_5min = genome[16]
                start_signal_5min = genome[17]
                start_macd_15min = genome[18]
                start_signal_15min = genome[19]
                end_macd_5min = genome[16]
                end_signal_5min = genome[17]
                end_macd_15min = genome[18]
                end_signal_15min = genome[19]

                # MAX条件
                max_threshold_5min = step_rate_5min * step_size_5min * self.max_histogram_5min
                max_threshold_5min += start_macd_5min * self.start_macd_5min
                max_threshold_5min += start_signal_5min * self.start_signal_5min
                max_threshold_5min += end_macd_5min * macd_5min
                max_threshold_5min += end_signal_5min * signal_5min
                max_threshold_15min = step_rate_15min * step_size_15min * self.max_histogram_15min
                max_threshold_15min += start_macd_15min * self.start_macd_15min
                max_threshold_15min += start_signal_15min * self.start_signal_15min
                max_threshold_15min += end_macd_15min * macd_15min
                max_threshold_15min += end_signal_15min * signal_15min
                # 降下条件
                decrease_threshold_5min = self.max_histogram_5min * decrease_rate_5min
                decrease_threshold_15min = self.max_histogram_15min * decrease_rate_15min

                if not self.max_price:
                    self.max_price = price
                else:
                    if self.max_price < price:
                        self.max_price = price

                sell = self.and_gate(
                    max_threshold_15min < self.max_histogram_15min,
                    histogram_15min < decrease_threshold_15min,
                    max_threshold_5min < self.max_histogram_5min,
                    histogram_1min < decrease_threshold_5min,
                )

                if self.max_price * price_rate > price:
                    sell_price = True
                else:
                    sell_price = False

                if sell or sell_price:
                    operation = self.SELL
                    self.max_price = None
                else:
                    operation = self.STAY
            else:
                operation = self.STAY
        else:
            operation = self.STAY

        return operation, float(self.df_signal.tail(1).price)

    def fetch_recent_data(self):
        """
        現在のtickerのapiを叩いて、最新の取引値を追加してデータを更新する
        """
        ticker = self.__api_gateway.use_ticker(pair=self.__pair)
        ticker = float(ticker['last'])
        tail = self.df_signal.tail(1)

        if self.count_15min == 15:
            self.count_15min = 1
            short_15min = self.__exponential_moving_average(
                ticker, float(tail.short_15min), self.__short_term)
            long_15min = self.__exponential_moving_average(
                ticker, float(tail.long_15min), self.__long_term)
            macd_15min = short_15min - long_15min
            signal_15min = self.__exponential_moving_average(
                macd_15min, float(tail.signal_15min), self.__signal)
            histogram_15min = macd_15min - signal_15min
        else:
            self.count_15min += 1
            short_15min = float(tail.short_15min)
            long_15min = float(tail.long_15min)
            macd_15min = float(tail.macd_15min)
            signal_15min = float(tail.signal_15min)
            histogram_15min = float(tail.histogram_15min)

        check_5min = self.__check_5min()

        if check_5min:
            short_5min = self.__exponential_moving_average(
                ticker, float(tail.short_5min), self.__short_term)
            long_5min = self.__exponential_moving_average(
                ticker, float(tail.long_5min), self.__long_term)
            macd_5min = short_5min - long_5min
            signal_5min = self.__exponential_moving_average(
                macd_5min, float(tail.signal_5min), self.__signal)
            histogram_5min = macd_5min - signal_5min
        else:
            short_5min = float(tail.short_5min)
            long_5min = float(tail.long_5min)
            macd_5min = float(tail.macd_5min)
            signal_5min = float(tail.signal_5min)
            histogram_5min = float(tail.histogram_5min)

        short_1min = self.__exponential_moving_average(ticker, short_5min,
                                                       self.__short_term)
        long_1min = self.__exponential_moving_average(ticker, long_5min,
                                                      self.__long_term)
        macd_1min = short_1min - long_1min
        signal_1min = self.__exponential_moving_average(
            macd_1min, signal_5min, self.__signal)
        histogram_1min = macd_1min - signal_1min

        add = pd.Series([
            ticker, short_15min, long_15min, short_5min, long_5min, short_1min,
            long_1min, macd_15min, macd_5min, macd_1min, signal_15min,
            signal_5min, signal_1min, histogram_15min, histogram_5min,
            histogram_1min
        ],
                        index=[
                            'price', 'short_15min', 'long_15min', 'short_5min',
                            'long_5min', 'short_1min', 'long_1min',
                            'macd_15min', 'macd_5min', 'macd_1min',
                            'signal_15min', 'signal_5min', 'signal_1min',
                            'histogram_15min', 'histogram_5min',
                            'histogram_1min'
                        ],
                        name=len(self.df_signal) - 1)

        self.df_signal = self.df_signal.append(add)
        self.df_signal = self.df_signal.loc[1:]

    def recognize(self):
        """
        最近の状況を認識する
        """
        size = len(self.df_signal)
        part = self.df_signal.loc[size - 1]
        self.__check_trend(histogram_15min=float(part.histogram_15min),
                           histogram_5min=float(part.histogram_5min))
        check_macd_15min = False
        pre_macd_15min = float(part.macd_15min)
        iteration = 2
        change_15min = False
        change_5min = False
        while True:
            part = self.df_signal.loc[size - iteration]
            histogram_15min = float(part.histogram_15min)
            histogram_5min = float(part.histogram_5min)
            macd_15min = float(part.macd_15min)
            macd_5min = float(part.macd_5min)
            signal_15min = float(part.signal_15min)
            signal_5min = float(part.signal_5min)

            if pre_macd_15min == macd_15min and check_macd_15min:
                self.count_15min += 1
            else:
                check_macd_15min = True

            pre_trend_15min = self.trend_15min
            pre_trend_5min = self.trend_5min
            self.__check_trend(histogram_15min=histogram_15min,
                               histogram_5min=histogram_5min)

            # 山の終わり
            if pre_trend_15min != self.trend_15min and not change_15min:
                change_15min = True
                self.start_macd_15min = macd_15min
                self.start_signal_15min = signal_15min

            # 山の終わり
            if pre_trend_5min != self.trend_5min and not change_5min:
                change_5min = True
                self.start_macd_5min = macd_5min
                self.start_signal_5min = signal_5min

            if not change_15min:
                self.area_15min.append(histogram_15min)
                if abs(self.max_histogram_15min) < abs(histogram_15min):
                    self.max_histogram_15min = histogram_15min

            if not change_5min:
                self.area_5min.append(histogram_5min)
                if abs(self.max_histogram_5min) < abs(histogram_5min):
                    self.max_histogram_5min = histogram_5min

            if change_5min and change_15min:
                break
            iteration += 1

        self.df_signal = self.df_signal.tail(10).reset_index(drop=True)

    def __check_trend(self, histogram_15min, histogram_5min):
        if histogram_15min >= 0:
            self.trend_15min = self.PLUS
        elif histogram_15min < 0:
            self.trend_15min = self.MINUS
        if histogram_5min >= 0:
            self.trend_5min = self.PLUS
        elif histogram_5min < 0:
            self.trend_5min = self.MINUS

    def __check_5min(self):
        if self.count_5min == 5:
            self.count_5min = 1
            return True
        else:
            self.count_5min += 1
            return False

    def make_data_frame(self):
        """
        データを作成する
        """
        df_price = self.make_price_data_frame()
        df_15min, df_5min = self.normalize_data_frame(df=df_price)
        df_macd, df_15min, df_5min = self.first_sma_data_frame(
            df_15min, df_5min)
        df_macd = self.make_macd_data_frame(df_macd, df_5min)
        self.df_signal = self.make_signal_data_frame(df_macd)

    def make_signal_data_frame(self, df_macd):
        part = df_macd.loc[:self.__signal * 3 - 1]
        sma_15min = float(
            np.sum(np.unique(part.macd_15min.values)) / self.__signal)
        sma_5min = float(
            np.sum(part.loc[self.__signal * 2:].macd_5min.values) /
            self.__signal)
        df_macd = df_macd.loc[self.__signal * 3:].reset_index(drop=True)
        df_signal = pd.DataFrame([[
            part.tail(1).price,
            part.tail(1).short_15min,
            part.tail(1).long_15min,
            part.tail(1).short_5min,
            part.tail(1).long_5min,
            part.tail(1).short_5min,
            part.tail(1).long_5min,
            part.tail(1).macd_15min,
            part.tail(1).macd_5min,
            part.tail(1).macd_5min,
            sma_15min,
            sma_5min,
            sma_5min,
            part.tail(1).macd_15min - sma_15min,
            part.tail(1).macd_5min - sma_5min,
            part.tail(1).macd_5min - sma_5min,
        ]],
                                 columns=[
                                     'price',
                                     'short_15min',
                                     'long_15min',
                                     'short_5min',
                                     'long_5min',
                                     'short_1min',
                                     'long_1min',
                                     'macd_15min',
                                     'macd_5min',
                                     'macd_1min',
                                     'signal_15min',
                                     'signal_5min',
                                     'signal_1min',
                                     'histogram_15min',
                                     'histogram_5min',
                                     'histogram_1min',
                                 ])

        signal_15min = sma_15min
        signal_5min = sma_5min
        for macd_i in range(len(df_macd) - 1):
            if macd_i % 3 == 0 and macd_i != 0:
                signal_15min = self.__exponential_moving_average(
                    value=df_macd.loc[macd_i].macd_15min,
                    pre_value=signal_15min,
                    term=self.__signal)
            signal_5min = self.__exponential_moving_average(
                value=df_macd.loc[macd_i].macd_5min,
                pre_value=signal_5min,
                term=self.__signal)

            df_signal.loc[macd_i + 1] = [
                df_macd.loc[macd_i].price,
                df_macd.loc[macd_i].short_15min,
                df_macd.loc[macd_i].long_15min,
                df_macd.loc[macd_i].short_5min,
                df_macd.loc[macd_i].long_5min,
                df_macd.loc[macd_i].short_5min,
                df_macd.loc[macd_i].long_5min,
                df_macd.loc[macd_i].macd_15min,
                df_macd.loc[macd_i].macd_5min,
                df_macd.loc[macd_i].macd_5min,
                signal_15min,
                signal_5min,
                signal_5min,
                df_macd.loc[macd_i].macd_15min - signal_15min,
                df_macd.loc[macd_i].macd_5min - signal_5min,
                df_macd.loc[macd_i].macd_5min - signal_5min,
            ]
        return df_signal.loc[1:].reset_index(drop=True)

    def make_macd_data_frame(self, df_macd, df_5min):
        ema_15min_short = df_macd.loc[0].short_15min
        ema_15min_long = df_macd.loc[0].long_15min
        ema_5min_short = df_macd.loc[0].short_5min
        ema_5min_long = df_macd.loc[0].long_5min
        for i_5min in range(len(df_5min) - 1):
            if i_5min % 3 == 0 and i_5min != 0:
                ema_15min_short = self.__exponential_moving_average(
                    value=df_5min.loc[i_5min].price,
                    pre_value=ema_15min_short,
                    term=self.__short_term)
                ema_15min_long = self.__exponential_moving_average(
                    value=df_5min.loc[i_5min].price,
                    pre_value=ema_15min_long,
                    term=self.__long_term)

            ema_5min_short = self.__exponential_moving_average(
                value=df_5min.loc[i_5min].price,
                pre_value=ema_5min_short,
                term=self.__short_term)
            ema_5min_long = self.__exponential_moving_average(
                value=df_5min.loc[i_5min].price,
                pre_value=ema_5min_long,
                term=self.__long_term)

            df_macd.loc[i_5min + 1] = [
                df_5min.loc[i_5min + 1].price,
                ema_15min_short,
                ema_15min_long,
                ema_5min_short,
                ema_5min_long,
                ema_15min_short - ema_15min_long,
                ema_5min_short - ema_5min_long,
            ]
        return df_macd.loc[1:].reset_index(drop=True)

    def make_price_data_frame(self):
        """
        直近のロウソク足データ(2日分)から終値のデータフレームを作る
        :return: pandas.DataFrame 2日分のロウソク足データ
        """
        today = datetime.datetime.now(timezone('UTC'))
        yesterday = today - datetime.timedelta(days=1)
        today = today.astimezone(timezone('Asia/Tokyo'))
        yesterday = yesterday.astimezone(timezone('Asia/Tokyo'))
        print('Initializing Candlestick Data From', today.strftime('%Y-%m-%d'),
              'and', yesterday.strftime('%Y-%m-%d'))
        candlestick_today = self.__api_gateway.use_candlestick(
            time=today.strftime("%Y%m%d"),
            candle_type=self.__candle_type,
            pair=self.__pair)['candlestick'][0]['ohlcv']
        candlestick_yesterday = self.__api_gateway.use_candlestick(
            time=yesterday.strftime('%Y%m%d'),
            candle_type=self.__candle_type,
            pair=self.__pair)['candlestick'][0]['ohlcv']
        candlestick_yesterday.extend(candlestick_today)
        candlestick = candlestick_yesterday
        del candlestick_today
        del candlestick_yesterday
        # 終値のみを取り出す
        candlestick = np.asarray(candlestick, dtype=float)
        candlestick = candlestick[0:, 3]
        return pd.DataFrame(candlestick, columns=['price'])

    @staticmethod
    def normalize_data_frame(df):
        """
        終値のデータフレームを15min, 5min, に分けて正規化する
        :param df: pandas.DataFrame
        :return: pandas.DataFrame, pandas.DataFrame
        """
        # 3の倍数に揃える(古いデータを削る)
        df = df.loc[len(df) % 3:]
        df_15min = df.loc[::3].reset_index(drop=True)
        return df_15min, df

    @staticmethod
    def __exponential_moving_average(value, pre_value, term):
        return pre_value + (2 / (term + 1)) * (value - pre_value)

    def first_sma_data_frame(self, df_15min, df_5min):
        """
        :param df_15min:
        :param df_5min:
        :return: ['short_15min', 'long_15min', 'short_5min', 'long_5min''macd_15min', 'macd_5min'], price_15min, price_5min
        """
        sma_15min_short = self.sma_15min_short(df_15min)[0]
        sma_15min_long = self.sma_15min_long(df_15min)[0]
        data_15min = self.cut_for_ema_15min(df_15min)
        sma_5min_short = self.sma_5min_short(df_5min)[0]
        sma_5min_long = self.sma_5min_long(df_5min)[0]
        data_5min = self.cut_for_ema_5min(df_5min)
        ema = pd.DataFrame([[
            data_5min.loc[0].price,
            sma_15min_short,
            sma_15min_long,
            sma_5min_short,
            sma_5min_long,
            sma_15min_short - sma_15min_long,
            sma_5min_short - sma_5min_long,
        ]],
                           columns=[
                               'price',
                               'short_15min',
                               'long_15min',
                               'short_5min',
                               'long_5min',
                               'macd_15min',
                               'macd_5min',
                           ])
        return ema, data_15min, data_5min

    def sma_15min_short(self, data_15min):
        """
        15minの短期単純移動平均
        :param data_15min:
        :return: SMA, テスト用DataFrame
        """
        part = data_15min.loc[(self.__long_term -
                               self.__short_term):self.__long_term - 1]
        price_sum = np.sum(part.price.values)
        sma = float(price_sum / self.__short_term)
        return sma, part

    def sma_15min_long(self, data_15min):
        """
        15minの長期単純移動平均
        :param data_15min:
        :return: SMA, テスト用DataFrame
        """
        part = data_15min.loc[0:self.__long_term - 1]
        price_sum = np.sum(part.price.values)
        sma = float(price_sum / self.__long_term)
        return sma, part

    def sma_5min_short(self, data_5min):
        """
        5minの短期単純移動平均
        :param data_5min:
        :return: SMA, テスト用のDataFrame
        """
        # 15 = 5 * 3
        part = data_5min.loc[self.__long_term * 3 -
                             self.__short_term:self.__long_term * 3 - 1]
        price_sum = np.sum(part.price.values)
        sma = float(price_sum / self.__short_term)
        return sma, part

    def sma_5min_long(self, data_5min):
        """
        5minの長期単純移動平均
        :param data_5min:
        :return: SMA, テスト用のDataFrame
        """
        # 15 = 5 * 3
        part = data_5min.loc[self.__long_term * 3 -
                             self.__long_term:self.__long_term * 3 - 1]
        price_sum = np.sum(part.price.values)
        sma = float(price_sum / self.__long_term)
        return sma, part

    def cut_for_ema_15min(self, data_15min):
        """
        SMAで使った部分を切り捨てる
        :param data_15min:
        :return:
        """
        return data_15min[self.__long_term:].reset_index(drop=True)

    def cut_for_ema_5min(self, df):
        """
        :param df:
        :return:
        """
        return df[self.__long_term * 3:].reset_index(drop=True)

    @staticmethod
    def and_gate(*args):
        return all(args)
class Auto:
    BUY = 1
    STAY = 2
    SELL = 3
    RETRY = 4

    DEFAULT_TYPE = 'market'
    TYPE_LIMIT = 'limit'
    TYPE_MARKET = 'market'

    def __init__(self, adviser, pair, api_key=None, api_secret=None):
        """
        :param adviser:       bitbank.adviser テクニカル分析結果から売却の指示をするクラスのインスタンス
        :param pair:          string          通貨のペア
        :param api_key:
        :param api_secret:
        """
        self.adviser = adviser
        self.pair = pair
        self.coin = pair.split('_')[0]
        self.yen = pair.split('_')[1]
        self.api_gateway = ApiGateway(api_key=api_key, api_secret=api_secret)
        self.buying_price = None
        self.order_ids = None
        self.__line = Line()
        self.__start_price = self.fetch_price()

    def fetch_price(self):
        """
        開始時の価格を返す
        :return: string
        """
        ticker = self.api_gateway.use_ticker(pair=self.pair)
        return float(ticker['last'])

    @staticmethod
    def __side_to_japanese(side):
        if side == 'buy':
            japanese = '買い'
        else:
            japanese = '売り'
        return japanese

    @staticmethod
    def __status_to_japanese(status):
        if status == 'UNFILLED':
            japanese = '注文中'
        elif status == 'PARTIALLY_FILLED':
            japanese = '注文中(一部約定)'
        elif status == 'FULLY_FILLED':
            japanese = '約定済み'
        elif status == 'CANCELED_UNFILLED':
            japanese = '取消済'
        elif status == 'CANCELED_PARTIALLY_FILLED':
            japanese = '取消済(一部約定)'
        else:
            japanese = 'None'
        return japanese

    def loss_cut_message(self):
        message = "損切りを行いました。"
        self.__line(message=message)

    def error_message(self, message):
        message = "エラー発生!!\n" \
                  "===================\n" \
                  "" + message + "\n" \
                  "==================="
        self.__line(message=message)

    def market_selling_message(self):
        message = "指値売り注文をキャンセルしましたので、成行注文を行います。"
        self.__line(message=message)

    def cancel_order_message(self, result):
        side = self.__side_to_japanese(side=result['side'])
        status = self.__status_to_japanese(status=result['status'])
        message = "注文を取り消しました。\n" \
                  "===================\n" \
                  "" + result['pair'] + " " + side + "注文 " + status + "\n" \
                  "注文ID: {}\n" \
                  "時刻: {}\n" \
                  "価格: {}\n" \
                  "平均価格: {}\n" \
                  "数量: {}\n" \
                  "約定数量: {}\n" \
                  "===================".format(
                        result['order_id'],
                        now(),
                        result['price'],
                        result['average_price'],
                        result['start_amount'],
                        result['executed_amount'],
                  )
        message.replace('n', '%0D%0A')
        self.__line(message=message)

    def new_order_message(self, order, retry):
        side = self.__side_to_japanese(side=order.side)
        status = self.__status_to_japanese(status=order.status)
        message = "新規注文を行いました。\n" \
                  "===================\n" \
                  "" + order.pair + " " + side + "注文 " + status + "\n" \
                  "注文ID: {}\n" \
                  "時刻: {}\n" \
                  "価格: {}\n" \
                  "数量: {}\n" \
                  "再要求回数: {}\n" \
                  "===================".format(
                        order.order_id,
                        order.ordered_at,
                        order.price,
                        order.start_amount,
                        retry
                  )
        message.replace('n', '%0D%0A')
        self.__line(message=message)

    def contract_order_message(self):
        message = "約定しました。\n" \
                  "===================\n" \
                  "時刻: {}\n" \
                  "===================".format(now)
        message.replace('n', '%0D%0A')
        self.__line(message=message)

    def __operation_to_side(self, operation):
        if operation == int(self.BUY):
            return 'buy'
        elif operation == int(self.SELL):
            return 'sell'
        else:
            raise SchedulerCancelException()
Beispiel #13
0
class TestApiGateway(unittest.TestCase):
    def setUp(self):
        print('api_key: ', end="")
        api_key = ''
        print('api_secret: ', end="")
        api_secret = ''
        self.api_gateway = ApiGateway(api_key=api_key, api_secret=api_secret)
        self.order_id = None

    def test_use_depth(self):
        result = self.api_gateway.use_depth(pair='xrp_jpy')
        self.assertNotEqual(None, result['asks'])
        self.assertNotEqual(None, result['bids'])

    def test_use_ticker(self):
        result = self.api_gateway.use_ticker(pair='xrp_jpy')
        self.assertNotEqual(None, result['sell'])
        self.assertNotEqual(None, result['buy'])
        self.assertNotEqual(None, result['high'])
        self.assertNotEqual(None, result['low'])
        self.assertNotEqual(None, result['last'])
        self.assertNotEqual(None, result['vol'])
        result = self.api_gateway.use_ticker(pair='xrp_jpy')
        self.assertNotEqual(None, result['sell'])
        self.assertNotEqual(None, result['buy'])
        self.assertNotEqual(None, result['high'])
        self.assertNotEqual(None, result['low'])
        self.assertNotEqual(None, result['last'])
        self.assertNotEqual(None, result['vol'])

    def test_use_candlestick(self):
        result = self.api_gateway.use_candlestick(pair='xrp_jpy',
                                                  candle_type='5min',
                                                  time='20181130')
        self.assertNotEqual(None, result['candlestick'])
        self.assertEqual('5min', result['candlestick'][0]['type'])
        self.assertEqual(12 * 24, len(result['candlestick'][0]['ohlcv']))

    def test_order(self):
        # new_order
        print('price: ', end='')
        self.price = input()
        print('amount: ', end='')
        self.amount = input()
        print('side: ', end='')
        self.side = input()
        result = self.api_gateway.new_order(pair='xrp_jpy',
                                            price=self.price,
                                            amount=self.amount,
                                            side=self.side,
                                            order_type='limit')
        self.assertNotEqual(None, result['order_id'])
        self.assertEqual('xrp_jpy', result['pair'])
        self.assertEqual(self.side, result['side'])
        self.assertEqual('limit', result['type'])
        self.assertEqual(self.amount, int(result['start_amount']))
        self.assertNotEqual(None, result['executed_amount'])
        self.assertEqual(self.price, result['price'])
        self.assertNotEqual(None, result['average_price'])
        self.assertNotEqual(None, result['ordered_at'])
        self.assertNotEqual(None, result['status'])
        self.order_id = result['order_id']
        print(result)

        # cancel_order
        result = self.api_gateway.cancel_order(pair='xrp_jpy',
                                               order_id=self.order_id)
        self.assertEqual(self.order_id, result['order_id'])
        self.assertEqual('xrp_jpy', result['pair'])
        self.assertEqual(self.side, result['side'])
        self.assertEqual('limit', result['type'])
        self.assertEqual(self.amount, int(result['start_amount']))
        self.assertNotEqual(None, result['executed_amount'])
        self.assertEqual(self.price, result['price'])
        self.assertNotEqual(None, result['average_price'])
        self.assertNotEqual(None, result['ordered_at'])
        self.assertNotEqual(None, result['status'])
        print(result)

        # order_info
        result = self.api_gateway.use_orders_info(pair='xrp_jpy',
                                                  order_ids=[self.order_id])
        self.assertEqual(self.order_id, result['orders'][0]['order_id'])
        self.assertEqual('xrp_jpy', result['orders'][0]['pair'])
        self.assertEqual(self.side, result['orders'][0]['side'])
        self.assertEqual('limit', result['orders'][0]['type'])
        self.assertEqual(self.amount, int(result['orders'][0]['start_amount']))
        self.assertNotEqual(None, result['orders'][0]['executed_amount'])
        self.assertEqual(self.price, result['orders'][0]['price'])
        self.assertNotEqual(None, result['orders'][0]['average_price'])
        self.assertNotEqual(None, result['orders'][0]['ordered_at'])
        self.assertNotEqual(None, result['orders'][0]['status'])
        print(result)
class BollingerBandSMATiAdviser:
    """
    BollingerBandSMATiの内容にしたがって売買の指示を出す
    """
    UPPER = 0
    UPPER_UPPER = 1
    UPPER_MIDDLE = 2
    MIDDLE_LOWER = 3
    LOWER_LOWER = 4
    LOWER = 5

    POSITIVE_INCLINATION = 1.376
    NEGATIVE_INCLINATION = -1.376
    POSITIVE_MIDDLE_INCLINATION = 0.325
    NEGATIVE_MIDDLE_INCLINATION = -0.325

    HYPER_EXPANSION = 0
    EXPANSION = 1
    FLAT = 2
    SQUEEZE = 3
    HYPER_SQUEEZE = 4

    def __init__(self,
                 stock_term,
                 inclination_alpha,
                 pair,
                 candle_type='5min'):
        self.__recent_data = None
        self.__recent_sma = None
        self.__recent_sigma = None
        self.__volatility = None
        self.__last_location = None
        self.__pre_location = None
        self.__inclination_pattern = None
        self.__stock_term = stock_term
        self.__inclination_alpha = inclination_alpha
        self.__pair = pair
        self.__candle_type = candle_type
        self.__api_gateway = ApiGateway()
        self.__initialize()

    def __initialize(self):
        """
        直近のロウソク足データの終値でで初期化する
        """
        # 直近のロウソク足データを読み込む
        candlestick = self.__fetch_recent_candlestick()

        # 必要な分のロウソク足データのみを切り取る
        candlestick = self.slice_off_candlestick(candlestick=candlestick)

        # ロウソク足データの終値のみを取り出す
        data_list = list()
        for data_i in range(len(candlestick)):
            # 始値, 高値, 安値, 終値, 出来高, UnixTime
            data_list.append(candlestick[data_i][3])

        # データを使って計算する
        # 直近の単純移動平均線を求める
        self.__recent_sma = simple_moving_average(data=np.asarray(
            a=data_list, dtype=np.float32),
                                                  term=self.__stock_term)
        print(self.__recent_sma)
        # 標準偏差を求める(1値)
        self.__recent_sigma = standard_deviation(data=self.__recent_sma,
                                                 term=self.__stock_term)
        print(self.__recent_sigma)

        # ボラティリティーを求める
        self.__volatility = volatility(sma=self.__recent_sma[-1],
                                       std=self.__recent_sigma[-1])
        # 計算に使うデータはnumpyに変換
        self.__recent_data = np.asarray(a=data_list, dtype=np.float32)
        # 終値の位置を求める
        self.__location()

    def fetch_recent_data(self):
        """
        現在のtickerのapiを叩いて、最新の取引値を追加してデータを更新する
        """
        ticker = self.__api_gateway.use_ticker(pair=self.__pair)
        ticker = float(ticker['last'])

        # データを更新
        self.__recent_data = np.append(self.__recent_data, ticker)
        self.__recent_data = np.delete(self.__recent_data, 0)

        # 直近の単純移動平均線を求める
        self.__recent_sma = simple_moving_average(data=np.asarray(
            a=self.__recent_data, dtype=np.float32),
                                                  term=self.__stock_term)
        # 標準偏差を求める
        self.__recent_sigma = standard_deviation(data=self.__recent_sma,
                                                 term=self.__stock_term)
        # ボラティリティーを求める
        self.__volatility = volatility(sma=self.__recent_sma[-1],
                                       std=self.__recent_sigma[-1])
        # 終値の位置を求める
        self.__pre_location = self.__last_location
        self.__location()

    def __inclination(self):
        """
        単純移動平均の1次線形回帰
        :return: 傾きのパターン
        """
        recent_sma = self.__recent_sma[len(self.__recent_sma) -
                                       self.__stock_term:len(self.__recent_sma
                                                             )]
        print(len(self.__stock_term), len(recent_sma))
        min_sma = np.amin(recent_sma)
        # 最小値との差分だけの行列を作る
        t = recent_sma - np.full_like(a=recent_sma, fill_value=min_sma)
        t = t * 1000
        x = np.arange(start=0,
                      step=self.__inclination_alpha,
                      stop=self.__inclination_alpha * len(t))
        # 直線(1次多項式)の線形回帰
        # その傾きを取り出す
        inclination = linear_regression(x=x,
                                        t=t,
                                        basic_function=Polynomial(dim=2))[1]
        print('inclination: ' + str(inclination))

        if self.POSITIVE_INCLINATION < inclination:
            inclination_pattern = self.HYPER_EXPANSION
        elif (self.POSITIVE_MIDDLE_INCLINATION <
              inclination) and (inclination <= self.POSITIVE_INCLINATION):
            inclination_pattern = self.EXPANSION
        elif (self.NEGATIVE_MIDDLE_INCLINATION <= inclination) and (
                inclination <= self.POSITIVE_MIDDLE_INCLINATION):
            inclination_pattern = self.FLAT
        elif (self.NEGATIVE_INCLINATION <= inclination) and (
                inclination < self.NEGATIVE_MIDDLE_INCLINATION):
            inclination_pattern = self.SQUEEZE
        elif inclination < self.NEGATIVE_INCLINATION:
            inclination_pattern = self.HYPER_SQUEEZE
        else:
            raise TypeError('inclination is None')
        return inclination_pattern

    def slice_off_candlestick(self, candlestick):
        """
        与えられたロウソク足データの必要な部分だけを切り取って返す関数
        :param candlestick: list ロウソク足データ
        :return: list
        """
        # 単純移動平均線 + 標準偏差 で(期間 - 1) * 1 を余分に使う
        data_size = self.__stock_term * 2 - 1
        candlestick_size = len(candlestick)
        if candlestick_size < data_size:
            raise TypeError('candlestick not have much length',
                            candlestick_size, data_size)
        # [start:stop:steps] stopは含まれない
        return candlestick[candlestick_size - data_size:candlestick_size]

    def __fetch_recent_candlestick(self):
        """
        直近のロウソク足データを2日分読み込む
        :return: list 2日分のロウソク足データ
        """
        today = datetime.datetime.now(timezone('UTC'))
        yesterday = today - datetime.timedelta(days=1)
        today = today.astimezone(timezone('Asia/Tokyo'))
        yesterday = yesterday.astimezone(timezone('Asia/Tokyo'))
        print('Initializing Candlestick Data From', today.strftime('%Y-%m-%d'),
              'and', yesterday.strftime('%Y-%m-%d'))
        candlestick_today = self.__api_gateway.use_candlestick(
            time=today.strftime("%Y%m%d"),
            candle_type=self.__candle_type,
            pair=self.__pair)['candlestick'][0]['ohlcv']
        candlestick_yesterday = self.__api_gateway.use_candlestick(
            time=yesterday.strftime('%Y%m%d'),
            candle_type=self.__candle_type,
            pair=self.__pair)['candlestick'][0]['ohlcv']
        candlestick_yesterday.extend(candlestick_today)
        candlestick = candlestick_yesterday
        del candlestick_today
        del candlestick_yesterday
        return candlestick

    def __location(self):
        """
        価格の位置を求める
        """
        end_price = self.__recent_data[-1]
        if self.__volatility['double_upper'] < end_price:
            self.__last_location = self.UPPER
        elif (self.__volatility['upper'] <
              end_price) and (end_price <= self.__volatility['double_upper']):
            self.__last_location = self.UPPER_UPPER
        elif (self.__volatility['sma'] <
              end_price) and (end_price <= self.__volatility['upper']):
            self.__last_location = self.UPPER_MIDDLE
        elif (self.__volatility['lower'] <=
              end_price) and (end_price <= self.__volatility['sma']):
            self.__last_location = self.MIDDLE_LOWER
        elif (self.__volatility['double_lower'] <=
              end_price) and (end_price < self.__volatility['lower']):
            self.__last_location = self.LOWER_LOWER
        elif end_price < self.__volatility['double_lower']:
            self.__last_location = self.LOWER
        else:
            raise TypeError()

    def operation(self, genome, has_coin):
        """
         データを更新して、複数個のシグマと前回、現在の終値の位置から取引の方針を決める
        :param genome:
        :param has_coin:
        :return: const int 取引方針をあらわす定数, float 最新の価格
        """
        self.__inclination_pattern = self.__inclination()
        action = self.determine_action(genome=genome, has_coin=has_coin)
        return action, self.__recent_data[-1]

    def determine_action(self, genome, has_coin):
        """
        終値、上部バンド、下部バンドから(買い,売り,保持)を決める
        ※ 遺伝子の特徴
        [(前回の終値位置0~5 * 1)(現在の終値位置0~5 * 6)(傾きのパターン0~4 * 36)(ビットコインを持っているか0~1 * 180)]
        """
        if has_coin:
            has_coin = 1
        else:
            has_coin = 0
        return genome[self.__pre_location * 1 + self.__last_location * 6 +
                      self.__inclination_pattern * 36 + has_coin * 180]

    def get_recent_data(self):
        """
        テスト用のゲッター
        :return: numpy
        """
        return self.__recent_data