Python AnyTrading - 投資の強化学習環境を試す①

AnyTradingは、FXや株式のトレーディングアルゴリズムを試すための強化学習環境です

インストール

下記のコマンドを実行しAnyTradingの実行環境をインストールします。

1
2
3
4
pip install gym-anytrading
pip install stable-baselines
pip install tensorflow==1.14.0

ランダム投資

ランダムに投資を行う処理を実装します。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import gym
import gym_anytrading
import matplotlib.pyplot as plt
from gym_anytrading.envs import TradingEnv, ForexEnv, StocksEnv, Actions, Positions
from gym_anytrading.datasets import FOREX_EURUSD_1H_ASK, STOCKS_GOOGL
from stable_baselines.common import set_global_seeds

# 環境を生成(frame_boundはデータセット内の訓練範囲を開始行数と終了行数で指定)
env = gym.make('forex-v0', frame_bound=(50, 100), window_size=10)

# シードの指定
env.seed(0)
set_global_seeds(0)

# ランダム行動による動作確認
state = env.reset()
while True:
action = env.action_space.sample()

# 1ステップ実行
state, reward, done, info = env.step(action)

# エピソード完了
if done:
print('info:', info)
break

# グラフのプロット
plt.cla()
env.render_all()
plt.show()

実行結果は下記のとおりです。

[実行結果]

info: {'total_reward': 85.50000000000279, 'total_profit': 0.9914207128440394, 'position': 0}

累計報酬(total_reward)、純利益(total_profit)、ポジション(position:0がショート、1がロング)が表示されます。
ランダムの割には利益が上がっています。

また下記のようなグラフが表示されます。

結果

赤●が「0:Sell」で落ちる予想、緑●が「1:Buy」で上がる予想を表します。

Python - 環境変数の取得

osモジュールのenviron変数には様々な環境変数が辞書型で格納されています。

環境変数の取得

[コード]

1
2
3
4
5
import os

print(os.environ)

print(os.environ['PATH'])

実行結果は下記のとおりです。

[実行結果]

environ({'ALLUSERSPROFILE': 'C:\\ProgramData', 'APPDATA': 'C:\\Users\\xxxx\\AppData\\Roaming',
(以下省略)
C:\ProgramData\Oracle\Java\javapath;C:\Util\Anaconda3;
(以下省略)

環境変数の設定が必要な処理をする場合に、実行前に設定を確認し問題があればアラート表示するなどの使い方ができると思います。

Python - 数値型

数値型のいろいろな表現をまとめてみました。

int型

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 10進数
num = 12
# => 12

# 8進数
num = 0o16
# => 14

# 16進数
num = 0xf2
# => 242

# 2進数
num = 0b1100
# => 12

float型

[コード]

1
2
3
4
5
6
7
8
9
10
num = 1.2
# => 1.2

# 指数表記 1.2×10の3乗
num = 1.2e3
# => 1200.0

# 指数表記 1.2×10のマイナス3乗
num = 1.2e-3
# => 0.0012

Python - グローバル変数、ローカル変数の表示

組み込みのglobals関数locals関数を使うと、現在のスコープのグローバル変数、ローカル変数を表示することができます。

グローバル変数、ローカル変数の表示

[コード]

1
2
3
4
5
6
7
8
9
10
GLOBAL_AVR = 123
def func():
x = 3
print('グローバル変数')
print(globals())
print()
print('ローカル変数')
print(locals())

func()

実行結果は下記のとおりです。

グローバル変数
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'GLOBAL_AVR': 123, 'func': }

ローカル変数
{'x': 3}

Python Image - 画像を編集する

Imageライブラリを使うとPythonから画像を編集することができます。

インストール

下記のコマンドを実行し、Imageライブラリをインストールします。

1
pip install PIL

ログ出力

基本的な画像処理をまとめて実行します。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from PIL import Image

# 画像ファイルを開く
image = Image.open('a.jpg')

# 画像のサイズを変更(横幅・縦幅)
image = image.resize([256, 256])
# 画像ファイルを出力
image.save('b.png')

# 回転させる
image = image.rotate(45)
# 画像ファイルを出力
image.save('c.png')

# 反転させる
image = image.transpose(Image.FLIP_LEFT_RIGHT) # 左右対称
#image = image.transpose(Image.FLIP_TOP_BUTTOM) # 上下対象
# 画像ファイルを出力
image.save('d.png')

# 切り貼り
part = image.crop((0, 0, 64, 64)) # 左、上、右、下
image.paste(part, (10, 10)) # 左、上
image.save('e.png')

Python Logging - ログを出力する

Pythonでログの出力・制御を行うためには、loggingモジュールを使用します。

標準出力とファイルへの出力や、重要度に応じた出力の制御、書式の設定などが可能です。

ログ出力

今回は、ファイルと標準出力にログを出力します。

またログの書式設定とログローテーションの設定も行います。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import logging
import logging.handlers
import sys

# 適当な名前を付けてLoggerオブジェクトを生成
logger = logging.getLogger('test_log')

# デバッグレベルを指定
# logging.CRITICAL(一番高いレベル)
# logging.ERROR
# logging.WARNING
# logging.INFO
# logging.DEBUG(一番低いレベル)
logger.setLevel(logging.DEBUG)

# ログ出力の書式設定
formatter = logging.Formatter('%(asctime)s[%(levelname)s] %(message)s')

# ファイル出力の設定(ログローテーション設定あり)
#file_handler = logging.FileHandler('test.log')
file_handler = logging.handlers.RotatingFileHandler('test.log', maxBytes=1024, backupCount=5)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)

# 標準出力の設定
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)

logger.debug('debug test.')
logger.info('info test.')
logger.warning('warning test.')
logger.error('error test.')
logger.critical('critical test.')

実行結果は下記のとおりです。

[実行結果]

2020-04-26 18:40:15,631[DEBUG] debug test.
2020-04-26 18:40:15,636[INFO] info test.
2020-04-26 18:40:15,639[WARNING] warning test.
2020-04-26 18:40:15,644[ERROR] error test.
2020-04-26 18:40:15,648[CRITICAL] critical test.

test.logファイルにも同様の内容が出力されます。

Python - DataFrameでソートと反転を行う

DataFrameではソートや反転を容易に行うことができます。

ソート

ソートするにはDataFrameのsort_values関数を使います。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd

# 身長・体重・性別のデータフレームを作成
tbl = pd.DataFrame({
'weight': [80.0, 70.4, 65.5, 45.9, 51.2, 72.5],
'height': [170, 180, 155, 143, 154, 160],
'gender': ['f', 'm', 'm', 'f', 'f', 'm']
})

print('身長をキーにソート')
print(tbl.sort_values(by='height'))
print()

print('体重を降順でソート')
print(tbl.sort_values(by='weight', ascending=False))

実行結果は下記のとおりです。

[実行結果]

身長をキーにソート
   weight  height gender
3    45.9     143      f
4    51.2     154      f
2    65.5     155      m
5    72.5     160      m
0    80.0     170      f
1    70.4     180      m

体重を降順でソート
   weight  height gender
0    80.0     170      f
5    72.5     160      m
1    70.4     180      m
2    65.5     155      m
4    51.2     154      f
3    45.9     143      f

反転

反転するにはDataFrameのT属性を参照します。

[コード]

1
2
3
4
5
6
7
8
9
10
11
import pandas as pd

tbl = pd.DataFrame([
['A', 'B', 'C'],
['D', 'E', 'F'],
['G', 'H', 'I']
])

print(tbl)
print('----')
print(tbl.T)

実行結果は下記のとおりです。

[実行結果]

   0  1  2
0  A  B  C
1  D  E  F
2  G  H  I
----
   0  1  2
0  A  D  G
1  B  E  H
2  C  F  I

Python - DataFrameで任意のデータ抽出

DataFrameでは任意のデータを容易に抽出することができます。

キーでのデータ抽出

まず1次元のリストが入った辞書型データよりデータフレームを作成します。

このデータに対して、キーを指定することにより任意の列のデータを取得することができます。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import pandas as pd

# 身長・体重・性別のデータフレームを作成
tbl = pd.DataFrame({
'weight': [80.0, 70.4, 65.5, 45.9, 51.2, 72.5],
'height': [170, 180, 155, 143, 154, 160],
'gender': ['f', 'm', 'm', 'f', 'f', 'm']
})

# 体重の一覧を表示
print('体重の一覧')
print(tbl['weight'])
print()

# 体重と身長の一覧を表示
print('体重と身長の一覧')
print(tbl[['weight', 'height']])

実行結果は下記のとおりです。

[実行結果]

体重の一覧
0    80.0
1    70.4
2    65.5
3    45.9
4    51.2
5    72.5
Name: weight, dtype: float64

体重と身長の一覧
   weight  height
0    80.0     170
1    70.4     180
2    65.5     155
3    45.9     143
4    51.2     154
5    72.5     160

スライスでのデータ抽出

任意の行を抽出したい場合は、Pythonの標準型であるリストを同じようにスライスを使うことができます。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd

# 身長・体重・性別のデータフレームを作成
tbl = pd.DataFrame({
'weight': [80.0, 70.4, 65.5, 45.9, 51.2, 72.5],
'height': [170, 180, 155, 143, 154, 160],
'gender': ['f', 'm', 'm', 'f', 'f', 'm']
})

# (0から数えて)2から3つ目のデータを表示
print('tbl[2:4]\n', tbl[2:4])
print()

# (0から数えて)3つ目以降のデータを表示
print('tbl[3s:]\n', tbl[3:])

実行結果は下記のとおりです。

[実行結果]

    weight  height gender
2    65.5     155      m
3    45.9     143      f

    weight  height gender
3    45.9     143      f
4    51.2     154      f
5    72.5     160      m

条件でのデータ抽出

条件を指定することにより、条件に合致したデータを抽出することができます。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd

# 身長・体重・性別のデータフレームを作成
tbl = pd.DataFrame({
'weight': [80.0, 70.4, 65.5, 45.9, 51.2, 72.5],
'height': [170, 180, 155, 143, 154, 160],
'gender': ['f', 'm', 'm', 'f', 'f', 'm']
})

print('身長が160以上のデータを表示')
print(tbl[tbl.height >= 160])
print()

print('性別が m のデータを表示')
print(tbl[tbl.gender == 'm'])

実行結果は下記のとおりです。

[実行結果]

身長が160以上のデータを表示
   weight  height gender
0    80.0     170      f
1    70.4     180      m
5    72.5     160      m

性別が m のデータを表示
   weight  height gender
1    70.4     180      m
2    65.5     155      m
5    72.5     160      m

Python - Pandasの基本データ

Pandasで扱う基本データは、DataFrameSiriesです。

DataFrame

DataFrameを定義するには、2次元のリストを引数に与えます。

[コード]

1
2
3
4
5
6
7
8
9
import pandas as pd

x = pd.DataFrame([
[10, 20, 30],
[40, 50, 60],
[70, 80, 90]
])

print(x)

実行結果は下記のとおりです。

[実行結果]

    0   1   2
0  10  20  30
1  40  50  60
2  70  80  90

実際のデータのほかに、列や行を意味するラベルも一緒に表示されていることが分かります。

Series

Seriesを定義するには、1次元のリストを引数に与えます。

[コード]

1
2
3
4
5
import pandas as pd

x = pd.Series([1.0, 3.0, 5.0, 7.0])

print(x)

実行結果は下記のとおりです。

[実行結果]

0    1.0
1    3.0
2    5.0
3    7.0
dtype: float64

インデックス番号付きで表示されるのが確認できます。また、データ型についても表示されます。

Python scikit-learn - アヤメの品種分類をクロスバリデーションで行う

アヤメの品種分類をクロスバリデーションで行います。

クロスバリデーションとは、最初に全てのデータを訓練データとテストデータに分割して、訓練データを用いて学習を行い、テストデータを用いて学習の妥当性を検証する手法です。

クロスバリデーションにはいろいろな手法がありますが、今回はK分割交差法をご紹介します。

【例 集合XをA,B,Cと3分割する場合】

(1) 集合Xを、AとBとCに分割します。
(2) Aとテストデータ、残りのB,Cを訓練データとして分類精度s1を求めます。
(3) Bとテストデータ、残りのA,Cを訓練データとして分類精度s1を求めます。
(4) Cとテストデータ、残りのA,Bを訓練データとして分類精度s1を求めます。
(5) 分類精度s1,s2,s3の平均を求め分類精度とします。

クロスバリデーション

実行するコードは下記の通りです。

[コード]

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd
from sklearn import svm, metrics, model_selection, datasets

# アヤメのCSVデータを読み込む
iris = datasets.load_iris()

# データの学習
clf = svm.SVC()
scores = model_selection.cross_val_score(clf, iris.data, iris.target, cv=5)

# 正答率を求める
print('各正解率:', scores)
print('正解率:', scores.mean())

9行目のcv=5で分割数を5に設定しています。

model_selection.cross_val_score関数1つで、複数回の検証を行えるのは大変便利です。


実行結果は次のようになります。

[実行結果]

各正解率: [0.96666667 0.96666667 0.96666667 0.93333333 1.        ]
正解率: 0.9666666666666666

正答率96%以上と十分な結果となります。

© 2024 Playing with Python All Rights Reserved.
Theme by hipaper