Edited at

遺伝的アルゴリズムでFX自動売買 その2 進化する売買AIの実装

More than 3 years have passed since last update.


前回の記事

pythonと遺伝的アルゴリズムで作るFX自動売買システム その1


今回作るモノ

前回のその1では基本的なAIと全体の仕組みを書いたので今回は複雑な売買AIを定義して、実際に遺伝的アルゴリズムで進化させていきます。


複雑な売買AIを定義

■ 仕様

現在レート、4時間平均レート、24時間平均レート、過去25営業日の最高値と最安値、過去25営業日の最高値と最安値から何日経過したかで、現在の相場をパターン分けし過去10年の売買データから適切(適切な値は遺伝的アルゴリズムで計算して過去のデータから求める)な注文を行う。

■ 動作例

通貨:ドル円

現在時刻: 2015年10月1日 10:00:00

現在レート: 120.00円

4時間平均レート: 119.80円

24時間平均レート: 119.40円

過去25営業日の最高値: 121.75円

過去25営業日の最安値: 117.25円

過去25営業日の最高値からの経過日数: 2日

過去25営業日の最安値からの経過日数: 8日

注文内容: 120円で100単位BUY、利益確定は120.60円、損切りは119.75円


genetic.py

# -*- coding: utf-8 -*-

import random
import datetime
from enum import Enum

def order(ai_order):
_base = "OrderDone:{}, Limit:{}, Stop-Limit:{}"
print _base.format(ai_order.order_type,
ai_order.limit,
ai_order.stop_limit)

class OrderType(Enum):
Buy = 1
Wait = 0
Sell = -1

class Rate(object):
start_at = datetime.datetime(2015, 10, 1, 10, 0, 0)
bid = float(120.00) # 現在のレート
h4 = float(119.80) # 過去4時間のレート平均
h24 = float(119.40) # 過去24時間のレート平均
low_25d = float(117.25) # 過去25営業日の最安値
high_25d = float(121.75) # 過去25営業日の最高値
low_25d_passed_day = 8 # 過去25営業日の最安値から何日経過したか
high_25d_passed_day = 2 # 過去25営業日の最高値から何日経過したか
base_tick = float(0.01) # 1tickあたりの最小売買単位

@classmethod
def get(cls, currency=None, start_at=None):
return Rate()

def get_rate(self, tick, is_add):
if is_add:
return self.bid + float(tick * self.base_tick)
else:
return self.bid - float(tick * self.base_tick)

class AIOrder(object):
def __init__(self, order_type, limit, stop_limit):
self.order_type = order_type
self.limit = limit
self.stop_limit = stop_limit

class MarketKeyMixin(object):
def get_key_h24(self):
"""
現在レートと過去24時間平均の差分を表すkeyを返却
例) H24:5
:rtype: str
"""

point = (self.rate.bid - self.rate.h24) / self.rate.base_tick
return 'H24:{}'.format(int(point / self.standard_tick))

def get_key_h4(self):
"""
現在レートと過去4時間平均の差分を表すkeyを返却
例) H4:0
:rtype: str
"""

point = (self.rate.bid - self.rate.h4) / self.rate.base_tick
return 'H4:{}'.format(int(point / self.standard_tick))

def get_key_low_25d(self):
"""
現在レートと過去25営業日中の最低値との乖離を表すkeyを返却
例) LOW:3
:rtype: str
"""

point = (self.rate.bid - self.rate.low_25d) / self.rate.base_tick
return 'LOW:{}'.format(int(point / self.standard_tick))

def get_key_high_25d(self):
"""
現在レートと過去25営業日中の最高値との乖離を表すkeyを返却
例) HIGH:2
:rtype: str
"""

point = (self.rate.bid - self.rate.high_25d) / self.rate.base_tick
return 'HIGH:{}'.format(int(point / self.standard_tick))

def get_key_low_passed_day(self):
"""
過去25営業日中の最低値から何日経過したか
例) LOW_PASSED_DAY:10
:rtype: str
"""

return 'LOW_PASSED_DAY:{}'.format(self.rate.low_25d_passed_day)

def get_key_high_passed_day(self):
"""
過去25営業日中の最高値から何日経過したか
例) HIGH_PASSED_DAY:1
:rtype: str
"""

return 'HIGH_PASSED_DAY:{}'.format(self.rate.high_25d_passed_day)

class AIParamValue(object):
"""
AIの動作データを定義するクラス
"""

def __init__(self, value, _min, _max):
self.value = value
self._min = _min
self._max = _max

def __repr__(self):
return "VALUE:{},MIN:{},MAX:{}".format(self.value,
self._min,
self._max)

def mutation(self):
"""
突然変異
"""

self.value = random.randint(self._min, self._max)
return self

class AIParamOrder(object):
"""
AIの動作データのうち発注時の動作を定義するクラス
"""

def __init__(self, order_type, limit, stop_limit, _min, _max):
self.order_type = order_type
self.limit = limit
self.stop_limit = stop_limit
self._min = _min
self._max = _max

def __repr__(self):
_base = "ORDER-TYPE:{},LIMIT:{},STOP-LIMIT:{},MIN:{},MAX:{}"
return _base.format(self.order_type,
self.limit,
self.stop_limit,
self._min,
self._max)

def mutation(self):
"""
突然変異
"""

self.order_type = random.choice(list(OrderType))
self.limit = random.randint(self._min, self._max)
self.stop_limit = random.randint(self._min, self._max)
return self

class AI(MarketKeyMixin):
DEFAULT_STANDARD_TICK = 30
DEFAULT_MIN = 15
DEFAULT_MAX = 120
# AIの動作データを保存
param = {
'DEFAULT_STANDARD_TICK': AIParamValue(DEFAULT_STANDARD_TICK, DEFAULT_MIN, DEFAULT_MAX)
}

def __init__(self, rate):
self.rate = rate

def order(self):
"""
発注する。
"""

order(self._get_order())

def get_key(self):
"""
Rateを解析・分類し、適切なKEYを生成する

# sample
'H24:5,H4:0,LOW:4,LOW_PASSED_DAY:3,HIGH:3,HIGH_PASSED_DAY:6'
"""
_base = [self.get_key_h24(),
self.get_key_h4(),
self.get_key_low_25d(),
self.get_key_high_25d(),
self.get_key_low_passed_day(),
self.get_key_high_passed_day()]
return ",".join(_base)

def _get_order(self):
"""
発注クラスを返却
rtype: AIOrder
"""

# Rateを解析する
key = self.get_key()
_o = self.param.get(key, None)
if _o is None:
# AIの注文データが存在しないときはランダム生成して保存
_o = self._get_random_order()
self.param[key] = _o

# 発注データの生成
limit_rate = self.rate.get_rate(_o.limit, True)
stop_limit_rate = self.rate.get_rate(_o.stop_limit, False)
return AIOrder(_o.order_type, limit_rate, stop_limit_rate)

def _get_random_order(self):
"""
AIの発注データが存在しないとき初期データをランダム生成する
"""

return AIParamOrder(random.choice(list(OrderType)),
0,
0,
self.DEFAULT_MIN,
self.DEFAULT_MAX).mutation()

def _get_order_type(self):
if self.rate.bid > self.rate.h24:
return OrderType.Buy
if self.rate.h24 > self.rate.bid:
return OrderType.Sell
return OrderType.Wait

@property
def standard_tick(self):
return self.param.get('DEFAULT_STANDARD_TICK').value

# レート取得
rate = Rate.get(currency='USDJPY', start_at=datetime.datetime.now())

# AI生成
ai = AI(rate)

# 発注
ai.order()

print ai.param

>>python genetic.py
>>OrderDone:OrderType.Sell, Limit:122.37, Stop-Limit:117.22
>>{'DEFAULT_STANDARD_TICK': VALUE:30,MIN:10,MAX:400, 'H24:1,H4:0,LOW:9,HIGH:-5,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:237,STOP-LIMIT:278,MIN:10,MAX:400}


このプログラムのポイントは2つあります。

1. AIは現在の相場をパターン分けしてのみを実施していること

2. AI自身に売買データが存在しない場合は_get_random_order関数で自分自身でランダムで行動を定義しているところ

この2つのポイントを抑えていると次項の遺伝的アルゴリズムによる自己進化するロジックを楽にキレイに書けるようになります。


作った売買AIで過去10年間のバックテスト実施

売買AIが完成したので過去10年分のデータでバックテストを実施します。1世代目のAIはランダム探索になるため、1万ドル単位の取引では年間100万円ずつ主に手数料で損失を出す悲しいAIが誕生してしまいました。


genetic.py

print ai.param

{
'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Wait,LIMIT:66,STOP-LIMIT:71,MIN:15,MAX:120,
'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:29,STOP-LIMIT:23,MIN:15,MAX:120,
'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:86,STOP-LIMIT:35,MIN:15,MAX:120,
'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:98,STOP-LIMIT:76,MIN:15,MAX:120,
'H24:-3,H4:0,LOW:12,HIGH:-2,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:78,STOP-LIMIT:64,MIN:15,MAX:120,
'H24:0,H4:0,LOW:9,HIGH:-5,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:92,STOP-LIMIT:62,MIN:15,MAX:120,
'H24:-3,H4:0,LOW:5,HIGH:-9,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:82,STOP-LIMIT:115,MIN:15,MAX:120,
'H24:0,H4:-3,LOW:0,HIGH:-15,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:108,STOP-LIMIT:109,MIN:15,MAX:120,
'H24:3,H4:-3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:100,STOP-LIMIT:42,MIN:15,MAX:120,
'H24:-3,H4:0,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:63,STOP-LIMIT:72,MIN:15,MAX:120,
'H24:3,H4:0,LOW:9,HIGH:-5,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Wait,LIMIT:64,STOP-LIMIT:89,MIN:15,MAX:120,
'H24:0,H4:0,LOW:5,HIGH:-9,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:94,STOP-LIMIT:16,MIN:15,MAX:120,
'H24:3,H4:-3,LOW:5,HIGH:-9,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Wait,LIMIT:50,STOP-LIMIT:117,MIN:15,MAX:120,
'H24:0,H4:3,LOW:9,HIGH:-5,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:112,STOP-LIMIT:24,MIN:15,MAX:120,
'H24:3,H4:0,LOW:-10,HIGH:-25,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:74,STOP-LIMIT:50,MIN:15,MAX:120,
'H24:3,H4:3,LOW:-10,HIGH:-25,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:20,STOP-LIMIT:111,MIN:15,MAX:120,
...
}


AIの中身は人間に扱いにくいmetaデータで構成されています。このAIを遺伝的アルゴリズムで進化させていきます。


遺伝的アルゴリズムで次世代AIを生成

■ 遺伝的アルゴリズムとは

遺伝的アルゴリズムは、ざっくり次の流れで遷移していきます。この項では3の交叉による次世代の生成を行います。

1.初期集団生成

2.評価

3.交叉による次世代の生成

4. 2~3でループして世代を重ねていきます。

■ 交叉による次世代の生成

交叉については様々な方法が提案されていますが、比較的有名かつ、計算効率が良いとされる方法を選択してみました。

■ 交叉と次世代生成の仕様

1. エリート主義(その世代の最良の個体を必ず次世代に残す選択方式)は行わない

2. 親はルーレット選択方式で選択する

3. 親2体を交叉して子を2体生成する

4. 交叉には2点交叉アルゴリズムを適用する

4. 各遺伝子が交叉時に1%の確率で突然変異が発生する

5. 各遺伝子が交叉時に85%の確率で2点交叉が発生する

6. 各遺伝子が交叉時に14%の確率で何も起こらない

7. 次世代は必ず20個

■ ルーレット選択方式について

例)

AI-1が利益100万円

AI-2が利益50万円

AI-3が利益10万円

のとき

AI-1が親に選択される確率は100/(100+50+10)=62.5%

AI-2が親に選択される確率は50/(100+50+10)=31.25%

AI-3が親に選択される確率は10/(100+50+10)=6.55%

■ 2点交叉アルゴリズムについて

Introduction to Genetic Algorithmsを参考にして実装しました。

スクリーンショット 2015-10-02 14.47.51.png

■ ご注意ください!

親の選択方法、交叉方法、突然変異方法は遺伝的アルゴリズムのパフォーマスに大きな影響を及ぼします。十分注意して手法を選択してください。


genetic_mixin.py

# -*- coding: utf-8 -*-

import random
import datetime
from enum import Enum

def mutation(_min, _max):
"""
突然変異
:param _min: int
:param _max: int
"""

return random.randint(_min, _max)

def cross_2point(a, b, _min, _max):
"""
2点交叉
:param a: int
:param b: int
"""

a = format(a, 'b')
b = format(b, 'b')
max_length = max([len(a), len(b)])
if len(a) < max_length:
a = '0' * (max_length - len(a)) + a
if len(b) < max_length:
b = '0' * (max_length - len(b)) + b
point1 = random.randint(1, max_length)
point2 = random.randint(1, max_length)
point_max = max(point1, point2)
point_min = min(point1, point2)
_a = a[:point_min] + b[point_min:point_max] + a[point_max:]
_b = b[:point_min] + a[point_min:point_max] + b[point_max:]
_a_point = int(_a, 2)
_b_point = int(_b, 2)

# 最小値以下や最大値以上のときは各値に丸める
def adjust(value, _min, _max):
if value > _max:
return _max
if value < _min:
return _min
return value

_a_point = adjust(_a_point, _min, _max)
_b_point = adjust(_b_point, _min, _max)

return _a_point, _b_point

def roulette_selection(ai_group):
"""
遺伝的アルゴリズム
ルーレット選択方式 スコアを重みとして選択
:param ai_group: list of AI
:rtype : AI
"""

# スコアがマイナスのときは補正値を使う
correct_value = min([ai.score(0) for ai in ai_group])
if correct_value > 0:
correct_value = 0

# ルーレット選択方式で計算する
total = sum([ai.score(correct_value) for ai in ai_group])
r = random.randint(0, total)
_total = 0
for ai in ai_group:
_total += ai.score(correct_value)
if r <= _total:
return ai
raise ValueError

class OrderType(Enum):
Buy = 1
Wait = 0
Sell = -1

@classmethod
def cross_2point(cls, a, b):
"""
交叉する
:param a: OrderType
:param b: OrderType
"""

value_a, value_b = cross_2point(a.value + 1, b.value + 1, 0, 2)
a_value = cls(value_a - 1)
b_value = cls(value_b - 1)
return a_value, b_value

class AIParamValue(object):
"""
AIの動作データを定義するクラス
"""

def __init__(self, value, _min, _max):
self.value = value
self._min = _min
self._max = _max

def __repr__(self):
return "VALUE:{},MIN:{},MAX:{}".format(self.value,
self._min,
self._max)

def cross_2point(self, b):
"""
2点交叉
"""

a = self
value_a, value_b = cross_2point(a.value, b.value, a._min, a._max)
a.value = value_a
b.value = value_b
return a, b

def mutation(self):
"""
突然変異
"""

self.value = random.randint(self._min, self._max)
return self

class AIParamOrder(object):
"""
AIの動作データのうち発注時の動作を定義するクラス
"""

def __init__(self, order_type, limit, stop_limit, _min, _max):
self.order_type = order_type
self.limit = limit
self.stop_limit = stop_limit
self._min = _min
self._max = _max

def __repr__(self):
_base = "ORDER-TYPE:{},LIMIT:{},STOP-LIMIT:{},MIN:{},MAX:{}"
return _base.format(self.order_type,
self.limit,
self.stop_limit,
self._min,
self._max)

def cross_2point(self, b):
"""
2点交叉
"""

a = self
# order_typeを交叉
order_type_a, order_type_b = OrderType.cross_2point(a.order_type, b.order_type)
a.order_type = order_type_a
b.order_type = order_type_b

# limitを交叉
limit_a, limit_b = cross_2point(a.limit, b.limit, a._min, a._max)
a.limit = limit_a
b.limit = limit_b

# stop_limitを交叉
stop_limit_a, stop_limit_b = cross_2point(a.stop_limit, b.stop_limit, a._min, a._max)
a.stop_limit = stop_limit_a
b.stop_limit = stop_limit_b

return a, b

def mutation(self):
"""
突然変異
"""

self.order_type = random.choice(list(OrderType))
self.limit = random.randint(self._min, self._max)
self.stop_limit = random.randint(self._min, self._max)
return self

class GeneticMixin(object):
@classmethod
def cross_over(cls, size, ai_group):
"""
遺伝的アルゴリズム
交叉 配合する
"""

# sizeは偶数であること
if size % 2 != 0:
raise AssertionError

# エリート主義(上位3名を残す)
# elite_group = sorted(ai_group, key=lambda x: x.score(0), reverse=True)[:3]
# elite_group = copy.deepcopy(elite_group)
# elite_group = [ai.incr_generation() for ai in elite_group]

# ルーレット選択方式で親を選択して交叉する
next_ai_group = []
while len(next_ai_group) != size:
next_ai_group += cls._cross(roulette_selection(ai_group),
roulette_selection(ai_group))
return next_ai_group

@classmethod
def _cross(cls, ai_a, ai_b):
"""
2体の親を交叉して、子供を2体生成
:param ai_a: AI
:param ai_b: AI
:return: list of AI
"""

# 世代をincr
generation = ai_a.generation + 1
child_a_param = {}
child_b_param = {}
for key in ai_a.param:
_value_a = ai_a.param.get(key)
_value_b = ai_b.param.get(key)
# 遺伝子毎に交叉する
_a, _b = cls._cross_value(_value_a, _value_b)
child_a_param[key] = _a
child_b_param[key] = _b

# 子を生成
child_a = cls.create_child(child_a_param, generation)
child_b = cls.create_child(child_b_param, generation)
return [child_a, child_b]

@classmethod
def create_child(cls, param, generation):
"""
次世代を生成する
:param param: dict
:param generation: int
:rtype: cls
"""

ai = cls()
ai.param = param
ai.generation = generation
return ai

@classmethod
def _cross_value(cls, value_a, value_b):
"""
遺伝子を交叉させる
:param value_a: AIParamValue or AIParamOrder
:param value_b: AIParamValue or AIParamOrder
:return: int or list
"""

if random.randint(1, 100) == 1:
# 突然変異
return value_a.mutation(), value_a.mutation()
elif random.randint(1, 100) <= 85:
# 2点交叉
return value_a.cross_2point(value_b)
else:
# 何もしない
return value_a, value_b

class AI(GeneticMixin):
DEFAULT_STANDARD_TICK = 30
DEFAULT_MIN = 15
DEFAULT_MAX = 120
param = {}
generation = 0 # 世代

def __repr__(self):
return "第{}世代AI PARAM:{}".format(self.generation, str(self.param))

def score(self, correct_value):
"""
バックテスト結果のscoreを返却
期間を通しての利益のこと

:param correct_value: float
:rtype : int
"""
return self.profit - correct_value

def get_random_order(self):
"""
AIの発注データが存在しないとき初期データをランダム生成する
"""

return AIParamOrder(random.choice(list(OrderType)),
0,
0,
self.DEFAULT_MIN,
self.DEFAULT_MAX).mutation()

def gen_random_ai_parame():
param = {
'DEFAULT_STANDARD_TICK': AIParamValue(AI.DEFAULT_STANDARD_TICK, AI.DEFAULT_MIN, AI.DEFAULT_MAX),
'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': AI().get_random_order(),
'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': AI().get_random_order(),
'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': AI().get_random_order(),
'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': AI().get_random_order(),
}
return param

# テスト 初期データ
print '~~~~~~~~~~~~~TEST DATA~~~~~~~~~~~~~'
ai1 = AI.create_child(gen_random_ai_parame(), 1)
ai1.profit = 100 * 10000
print ai1

ai2 = AI.create_child(gen_random_ai_parame(), 1)
ai2.profit = 50 * 10000
print ai2

ai3 = AI.create_child(gen_random_ai_parame(), 1)
ai3.profit = -100 * 10000
print ai3

ai4 = AI.create_child(gen_random_ai_parame(), 1)
ai4.profit = -500 * 10000
print ai4

ai_group = [ai1, ai2, ai3, ai4]

# 次世代AIの生成
print '~~~~~~~~~~~~~RESULT~~~~~~~~~~~~~'
ai_group_next_generation = AI.cross_over(20, ai_group)

for ai in ai_group_next_generation:
print ai

>>python genetic_mixin.py
~~~~~~~~~~~~~TEST DATA~~~~~~~~~~~~~
1世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:32,STOP-LIMIT:120,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:99,STOP-LIMIT:25,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Wait,LIMIT:30,STOP-LIMIT:20,MIN:15,MAX:120}
1世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:94,STOP-LIMIT:112,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Wait,LIMIT:24,STOP-LIMIT:101,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:66,STOP-LIMIT:79,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:78,STOP-LIMIT:81,MIN:15,MAX:120}
1世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Wait,LIMIT:94,STOP-LIMIT:35,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:103,STOP-LIMIT:112,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:18,STOP-LIMIT:38,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:20,STOP-LIMIT:89,MIN:15,MAX:120}
1世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Wait,LIMIT:42,STOP-LIMIT:20,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:46,STOP-LIMIT:76,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:104,STOP-LIMIT:43,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:40,STOP-LIMIT:109,MIN:15,MAX:120}
~~~~~~~~~~~~~RESULT~~~~~~~~~~~~~
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Wait,LIMIT:92,STOP-LIMIT:48,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:111,STOP-LIMIT:113,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:15,STOP-LIMIT:38,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:15,STOP-LIMIT:89,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:94,STOP-LIMIT:99,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:15,STOP-LIMIT:120,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:98,STOP-LIMIT:79,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:86,STOP-LIMIT:81,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:94,STOP-LIMIT:99,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:15,STOP-LIMIT:120,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:98,STOP-LIMIT:79,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:86,STOP-LIMIT:81,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:94,STOP-LIMIT:99,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:15,STOP-LIMIT:120,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:98,STOP-LIMIT:79,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:86,STOP-LIMIT:81,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:94,STOP-LIMIT:99,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:15,STOP-LIMIT:120,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:98,STOP-LIMIT:79,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:86,STOP-LIMIT:81,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:94,STOP-LIMIT:99,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:15,STOP-LIMIT:120,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:98,STOP-LIMIT:79,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:86,STOP-LIMIT:81,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:94,STOP-LIMIT:99,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:15,STOP-LIMIT:120,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:98,STOP-LIMIT:79,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:86,STOP-LIMIT:81,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Wait,LIMIT:92,STOP-LIMIT:48,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:111,STOP-LIMIT:113,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:15,STOP-LIMIT:38,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:15,STOP-LIMIT:89,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:94,STOP-LIMIT:99,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:15,STOP-LIMIT:120,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:98,STOP-LIMIT:79,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:86,STOP-LIMIT:81,MIN:15,MAX:120}
2世代AI PARAM:{'H24:-3,H4:3,LOW:-7,HIGH:-22,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:30,STOP-LIMIT:83,MIN:15,MAX:120, 'H24:3,H4:3,LOW:-4,HIGH:-19,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:55,STOP-LIMIT:96,MIN:15,MAX:120, 'DEFAULT_STANDARD_TICK': VALUE:30,MIN:15,MAX:120, 'H24:0,H4:3,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Buy,LIMIT:83,STOP-LIMIT:31,MIN:15,MAX:120, 'H24:0,H4:0,LOW:2,HIGH:-12,LOW_PASSED_DAY:8,HIGH_PASSED_DAY:2': ORDER-TYPE:OrderType.Sell,LIMIT:28,STOP-LIMIT:20,MIN:15,MAX:120}


だんだん結果が複雑になってきました。目で試験は厳しくなってくるので、ちゃんとテストコード書いていきましょう。


コラム:バグっていても利益が出るAI

もし売買部分の実装がバグが存在するとどうなるでしょうか?遺伝的アルゴリズムのスコアを売買収益に設定していると、バグがある状態で売買して、バグがある状態で収益が出るようにパラメータが最適化されていきます。実はバグがあっても利益がでるAI。当初なかなか納得できませんでした。そしてバグを直すと売買結果が変化するため、本番系を止めることもできず困ってしまいました。


おわりに

本投稿では複雑な売買AIの定義と遺伝的アルゴリズムでの進化を実装しました。自動売買の実装、OandaAPIの呼び出しの実装、AIの保存、世代毎の計算結果の記録など

まだ書き切れていないので、後日その3で紹介していきたいなーと思います。


その3書いてみました

遺伝的アルゴリズムでFX自動売買 その3 OandaAPIで実際に取引


関連記事

pythonと遺伝的アルゴリズムで作るFX自動売買システム その1

遺伝的アルゴリズムでFX自動売買 その2 進化する売買AIの実装

遺伝的アルゴリズムでFX自動売買 その3 OandaAPIで実際に取引