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

  • 351
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

前回の記事

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で実際に取引