FX BOT 4: AWS Cloud9へのBOT実装で注意すること5つ

Posted on November 4th, 2019Updated on February 28th, 2020
FX BOT 4: AWS Cloud9へのBOT実装で注意すること5つ

どんな記事

はじめて作成したBOTを、はじめてAWS Cloud9で稼働してみて気がついたことと、その対応のまとめ。長期間に渡って安定稼働するための注意点でもあると思います。今後も気がついたことがあれば追記していく予定です。

Cloud9の環境を python2.7 → python3.6

大まかな切り替えは以前の記事で完了していたが、aliasupdate-alternativesの変更も必要だった。以下の記事を参考に簡単に対応できた。

Pythonのaliasを変更

$ vi ~/.bashrc

alias python=python27alias python=python36に変更する。

$ source ~/.bashrc

出典元: 【Python】Cloud9上でPython3系を使うとき絶対にやっておくべき環境設定【AWS】

update-alternativesの設定

そもそもupdate-alternativesが何なのか。はじめて見た単語だったので調べてみた。ここでは、「類似のプログラムの内どちらを使用するかを指定する」ということをしているよう。

で、設定方法。

pythonの設定を開く
$ sudo update-alternatives --config python

バージョン別のPythonがいくつか表示されるので、/usr/bin/python3.6の番号を入力する。

ta-libのインストール

AWS cloud9 ta-libのインストールでつまづいたが、「Cloud9でTA-Libをインストールする - Qiita」で紹介されているコードですんなり解決できた。

wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
tar -zxvf ta-lib-0.4.0-src.tar.gz
cd ta-lib
./configure --prefix=/usr
make
sudo make install

sudo bash -c "echo "/usr/local/lib64" >> /etc/ld.so.conf"
sudo /sbin/ldconfig
sudo pip install ta-lib

出典元: Cloud9でTA-Libをインストールする - Qiita

Google APIへの接続

数日間、実際に継続運用してみると、短期間のテストでは見えなかった問題がいくつか発生した。それぞれ以下の方法で対処し、現在は問題なく稼働している。

トークンのリフレッシュが必要に

修正後のコードも記録しておく。gs_client.login()が該当のコード。

n = 0
while True :
  try :
    gs_client = gspread.authorize( self.google_credentials )
    gs_sh = gs_client.open_by_key( self.spreadsheet_key ).worksheet( sh_name )
    if self.google_credentials.access_token_expired :
        gs_client.login()
    return gs_sh.append_row( values ,'USER_ENTERED' )
  except APIError as e :
    self.__logger.error( f"SheetのAPIでエラー発生 : {e}" )
    self.__logger.error( f"{2**n}秒待機してやり直します" )
    time.sleep( 2 ** n )
    n = n + 1
  except RequestException as e :
      self.__logger.error( f"Requestでエラー発生 : {e}" )
      self.__logger.error( f"{2**n}秒待機してやり直します" )
      time.sleep( 2 ** n )
      n = n + 1

503エラーが発生 → APIの制限オーバー?

トークンリフレッシュが実装できて安心していたところ、今度は別のエラーが発生。以下が原因。

f01ad02cc1a92668af73714ed004cd19

出典元: Search returns error "503: Service Unavailable" - Google Search Appliance Help

つまり、APIの制限をオーバーしているらしい。

  • 500回/100秒 1プロジェクト(500 requests per 100 seconds per project)
  • 100回/100秒 1ユーザー(100 requests per 100 seconds per user)
  • 日ごとの制限はなし(There is no daily usage limit)

出典元: Usage Limits  |  Sheets API  |  Google Developers

回数を減らして無事解決。

稼働状況の把握

当初は、Cloud9上でのprintとGoogleシートのみで稼働状況を把握していたが以下に改善を行った。

稼働詳細:テキストのログ

  • 方法:サーバーにテキストでログを残す
  • 目的:正常に動作しているかの確認やエラー箇所の特定に使用する。大量にログを残しておく。

いくつかの記事を参考に、「Pythonのロギングを覚えた - Qiita」に掲載されているコードを組み込んだ。

def setup_logger(name, logfile='LOGFILENAME.txt'):
  logger = logging.getLogger(name)
  logger.setLevel(logging.DEBUG)
  
  # create file handler which logs even DEBUG messages
  fh = logging.FileHandler(logfile)
  fh.setLevel(logging.DEBUG)
  fh_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(name)s - %(funcName)s - %(message)s')
  fh.setFormatter(fh_formatter)
  
  # create console handler with a INFO log level
  ch = logging.StreamHandler()
  ch.setLevel(logging.INFO)
  ch_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', '%Y-%m-%d %H:%M:%S')
  ch.setFormatter(ch_formatter)
  
  # add the handlers to the logger
  logger.addHandler(fh)
  logger.addHandler(ch)
  return logger
# 各モジュールの最初のほうで、グローバルに宣言しておく
logger = setup_logger(__name__)

出典元: Pythonのロギングを覚えた - Qiita

以下は参考にした記事。

保留中の課題

大きな問題ではないが、以下が解決できていない。

稼働概要:Discordに通知

  • 方法:注文と売買をdiscordに通知
  • 目的:サクッと動作を確認する。スマホにPush通知がくるので便利。

LINE通知よりも便利なDiscord通知を使ってみよう!|asim|note」で簡単に実装できた。Discordは他にも使えそう。便利。

# coding: utf-8
import requests

def discord(message):
  # Discordで発行したWebhookのURLを入れる
  discord_webhook_url = 'あなたのWebhookURL'
  data = {"content": " " + message + " "}
  requests.post(discord_webhook_url, data=data)

discord('discord通知テスト')

出典元: LINE通知よりも便利なDiscord通知を使ってみよう!|asim|note

現在のポジションと損益:OANDA

  • 方法:OANDA
  • 目的:サクッと損益やチャート、トレード状況を確認する。

これは特に作業をしたわけではない。スマホにアプリを入れるだけ。この他にも、TradingViewのストラテジーでシグナルを確認できるようにもしている。

資金の推移と売買の履歴:Googleシート

  • 方法:Googleシート
  • 目的:統計を自動算出。損益の推移やトレード履歴を確認する。

元から実装していたもの。分析用。OANDAだけでは欲しい情報が記録されないので、OANDA+BOTの情報をすべて記録しておく。

システムのデーモン化

システムがエラーを吐かずに停止することが何回かあった。以下の仮説を立て、調査と対応を行った。

  • 「Run」で起動していることが原因?(起動時間の制限みたいなものがあり、勝手に停止してしまう?)
  • エラーを吐いていないだけで、エラーは起きている?

Cloud9 の Run で起動していることが原因?

実際の原因は特定できなかったが、起動方法を変更とデーモン化で同様の問題は起こらなくなった。デーモン化とは、特定のプログラムを永続化すること。

再起動でBOT独自の情報を引き継ぐように

今回の対応を行うにあたって、OANDAに保存されないBOT独自の情報を引き継ぐロジックを作成した。と言っても複雑なことをしたわけではなく、情報を都度サーバーに保存し、再起動時に読み込む処理を作成した。

バックアップする関数
def __backup( self ,data ) :
  data = str( data ).replace( 'nan' ,'np.nan' )
  self.__ss_backup( str( { 'datetime': self.__get_now() ,'FLAGS': data } ) )
  self.__txt_write( self.backup_file ,data )
バックアップを読み込む関数
def __load_backup( self ) :
  s = self.__txt_read( self.backup_file )
  if not s==False :
    # 文字列をコードとして実行する
    exec( f'self.FLAGS = {s}' )
    self.__count_positions()
    self.__is_init_on_tick = False
    self.__logger.info('ポジションとオーダーを読み込みました')
  else :
    # 初回起動としてOANDA側の初期化
    self.exit_all()
    self.cancel_all()
    self.__logger.info('情報がないため初回の起動として処理します')
初回のon_tickで読みに行く
def __on_tick_start( self ) :
  if self.__is_init_on_tick : self.__load_backup()

シェルスクリプトでpythonファイルを複数回動かす

Linux系はまったく詳しくなくて、調べてはじめて知ったことが多い。シェルスクリプトとはターミナルで実行できるスクリプトのことで、組み方でPythonファイルの無限ループを設定することもできる。

具体的には、以下のコードをシェルスクリプトファイル(「YOUR_BOT.sh」など)として保存し、

再起動するシェルスクリプト
while true; do
  python ./YOUR_BOT_FILE.py; sleep 5;
  echo "YOUR_BOT_FILE.py を再起動します"
done

以下のコードをターミナルで実行する。

シェルスクリプトを実行
$ ./YOUR_BOT.sh

すると、設定したPythonファイルが手動で停止するまで実行され続ける。

上記のサンプルは、直下に保存したファイルのみを対象とする。他の階層にあるファイルは別途パスを指定する必要がある。また、ターミナル上で「Ctrl+c」を2回押すことで停止することができる。

以下は参考にした記事。

サービスに登録する

前述のシェルスクリプトを用いた方法では、(おそらく)単一のプログラムにしか対応できない。「サービスへの登録」を行うことで複数のプログラムをデーモン化することができると理解している。(間違っているかもしれない)

今のところ単独のロジックしか回していないので対応は保留しているが、今後のために参考になりそうなリンクを残しておく。また、対応が完了したところで、この記事も更新したいと思う。

その他の対応方法

今回は実装しなかったが、以下のような方法もあるよう。

同じタグの記事
著者

タカハシ / 8年目の兼業トレーダー

元・日本料理の板前。現在は、投資やプログラミング、動画コンテンツの撮影・制作・編集などを。更新のお知らせは、各SNSやLINEで。LINEだと1対1でお話することもできます!

このブログと筆者について運用管理表

  • 記事をシェア
© Investment Tech Hack 2021.