自社開発の証券基幹システムにイノベーションを起こす!社内アイデアソン開催

f:id:monex_engineer:20190806153513p:plain

こんにちは。開発グループの田中です。
今回は、アイデアソンの企画運営をした事務局の方に記事を書いてもらいました。

マネックス証券でどのような取り組みがされているのか、社内の雰囲気をお伝えしたいと思います。


マネックス証券システム部門で開催されたアイデアソンのレポートです。

イデアソンとは『アイデア(Idea)とマラソン(Marathon) を合わせた造語で、同じテーマについて皆で集中的にアイデアを出し合うことにより、新たな発想を創出しようとする取り組みや、そうした取り組みを主とするイベント』です。

 

第1回GALAXYアイデアソンが、2018年8月~2019年3月にわたって開催されました。

長い期間をかけて行われたのは、2つのフェーズで業務時間外に取り組んだためです。

ステージ1 7月~9月 アイデアを練るフェーズ
 詳しいナレッジを持たない人が参加できるように技術を研究する期間

ステージ2 10月~3月 アイデアからより具体的な実証を行うフェーズ
 具体的に掘り下げることで現実的な課題を浮き彫りにする期間

 

『GALAXY』というのは数年間の開発期間を経て2017年1月にリリースしたマネックス証券の自社開発基幹システムの名称です。

f:id:monex_engineer:20190806131326j:plain

テーマは『新テクノロジーでGALAXYにイノベーションを起こす』

AI、RPA、DevOps、ブロックチェーン (KYC含む)、マイクロサービスアーキテクチャ疎結合API)、サーバーレスアーキテクチャAWSラムダ等)、モジュール化、ビジネスプロセスの細分化、デザインパターン、リーンアジャイル、マルチチャネル対応、業務アプリケーション連携(Slack,IoT等)...

様々なテクノロジーが基幹システムGALAXYに絡んでいることが制約事項で、それ以外は自由です。

7チーム20名がエントリーしました。

 

各チームのテーマと発表の様子を少しご紹介します。

MONEXによるMONEXのための開発標準

f:id:monex_engineer:20190806131633j:plain

◆DLT(分散管理台帳)

f:id:monex_engineer:20190806131647j:plain

◆AIおよびGALAXY適用分野の再検討と学習精度向上技術

f:id:monex_engineer:20190806131708j:plain

機械学習を用いた目論見書解析による業務効率化

f:id:monex_engineer:20190806131358j:plain

◆生体認証を用いた本人特定

f:id:monex_engineer:20190806131414j:plain

f:id:monex_engineer:20190806131429j:plain

◆AIと投信

f:id:monex_engineer:20190806131458j:plain

f:id:monex_engineer:20190806131513j:plain

◆コード自動生成

f:id:monex_engineer:20190806131545j:plain

 

開発本部長:安原さん

『「そんなの無理に決まっています」 から 「まずはやってみましょうか」の文化へ。
やってみたら意外とできることもある。
「やりましょうよ」と声が上がる集団を目指す。』

f:id:monex_engineer:20190806131616j:plain

 

私たちマネックス証券は、業界でも例を見ない証券基幹システムの内製化に取り組み、数年間の開発期間を経て2017年1月に自社システム「GALAXY」をリリースしました。

自社システムを持つメリットは、開発が低コストでスピーディーになり、ノウハウを社内に蓄積することはもちろん、社員が必要と思うものを社員の手で実現できるようになることです。

自分たちの手で運用・開発を行うために、社員の専門性を高める努力をしています。
勉強会、アイデアソン等の開催を通し、普段の業務では交流のないメンバーと一緒に作業したり、新技術の知見を深める取り組みも行っています。

社外の研修にも積極的に参加が奨励され、学ぶ意欲に応える環境があります。

 

次回、優勝チームと参加者アンケートをご紹介します。


いかがでしたか?

過去のアイデアソンについての記事を以下にまとめたので、あわせてご覧ください。

blog.tech-monex.com

blog.tech-monex.com

blog.tech-monex.com

FX

こんにちは。システム開発部 企画・設計Gの牛込です。

マネックス証券に転職してからは、4年半程になりました。
前職はITコンサル系の会社に所属していて主に金融システムを担当していました。
上記のような由縁で現在は主にFX(外国為替証拠金取引)、先物OP取引システムのプロジェクトを推進しています。

FXの過去

折角なのでFXのお話をさせてもらいます。日本では1998年の「新改正外為法」の施行により個人による為替取引が自由化されました。

黎明期は法規制が不十分な事もありよからぬ業者の出現や、システム面の不備等による問題が発生したりしました。(FXは怖いという認識もあったりしたそうです。)
まあそれも10年・20年と経過するにつれ、法規制はもちろん内部管理も充実していき立派に一つの金融取引として成長できたのかなと考えております。

FXPLUS

マネックス証券ではFXPLUSというサービスを展開しています。
以下は取引ツールであるMonex TraderFX(バックナンバーでも少し触れています。)

サービスの改善はもちろんですが、日々の安定稼働を願い精進しております。

f:id:monex_engineer:20190730140525p:plain

 サービスの改善はもちろんですが、日々の安定稼働を願い精進しております。
もう4年近く稼働しているシステムなのでそろそろリプレースの時期かなーと勝手に思う今日この頃です。

お仕事の後は・・・

f:id:monex_engineer:20190731082911j:plain

野球観戦! 
平日でもプレイボールに間に合うように会社を出ます。
ありきたりですがプライベートの時間はしっかりとれます。

 

ディープラーニングでそっくりな株価チャート取得してみた(ひとり20%ルールやってみた)

f:id:monex_engineer:20190723120959p:plain

こんにちは。システム開発部の諸です。 突然ですが、世界で一番イノベーションを起こしている企業といったら、みなさんはどの会社を思い浮かべるでしょうか?

私はGoogleだと思っています。(タダのGoogle好き) そのGoogleの社内では、イノベーションを起こすために日本では考えられない奇抜なルールがいくつか存在します。 その中の一つに「20%ルール」というものがあります。

ざっくり言えば、普段の業務のうち「80%を普段の業務、20%を自由な発想(イノベーション)に割り当てよう!」というルールです。 これは人事評価の対象になり、あのGmailAdSenseなどもこのルールから生まれたそうです。

日本では考えられない話ですね~。 そういうワケで今回のサブタイのマネックスで「ひとり20%ルールやってみた」をやってみました。

当然、普段の業務で20%も使えないので、業務の空き時間を使いKerasでそっくりな株式チャート取得してみました。

環境・ライブラリ

Windows 7
・Anaconda3-2019.03-Windows-x86_64.exe
・tensorflow
・keras

Anacondaは下記のサイトからダウンロードできます。
Anaconda Python/R Distribution - Free Download

Keras

ケラス?カラス?なんじゃそれ?
という方は、下記のサイトがわかりやすく解説してくれています。

www.sejuku.net qiita.com

Kerasでそっくりな株価チャート取得してみた

もしこんなテクニカル分析投資家がいたとしましょう。 「○○株式会社の株価チャートとそっくりなチャートの会社を知りたい!」

色々ググりながら、やっつけで作ってみました。

今回、使用したアルゴリズムはCNN(Convolutional Neural Network)です。

活性化関数には畳み込みの際にはRelu関数を使用し、最終的なクラス分類の際には分類でよく使われるSoftmax関数を使用しました。

ソース全文
#!/usr/bin/env python
# coding: utf-8
 
import os
import glob
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
 
from keras.preprocessing.image import load_img, img_to_array, array_to_img
from keras.preprocessing.image import random_rotation, random_shift, random_zoom
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Dense
from keras.layers.core import Dropout
from keras.layers.core import Flatten
from keras.models import Sequential
from keras.models import model_from_json
from keras.callbacks import LearningRateScheduler
from keras.callbacks import ModelCheckpoint
from keras.optimizers import Adam
from keras.utils import np_utils
 
PATH_DELIMITER = os.sep # パス区切り文字
ALF_MAX_NUM = 26 # アルファベットA-Zの個数
ALF_BEGIN_NUM = 65 # ASCIIコードのアルファベットの開始値
company_name = "" # 会社名
NPY_EXTENSION_NAME = ".npy"
DIR_PATH = "teach"
LABEL_NAME = ["reverse_u", "right_down", "right_up", "v"] # ラベル付けの種類
IMAGE_HEIGHT = 32
IMAGE_WIDTH = 32
 
# ランダムウォークしたチャートを生成
def out_random_chart(loop, dir="teach") :
    count = 0 # アルファベットのカウント
    for i in range(loop) :
        if count < ALF_MAX_NUM :
            company_name = chr(ALF_BEGIN_NUM + count)
        else :
            company_name = chr(ALF_BEGIN_NUM + (count // ALF_MAX_NUM - 1)) + chr(ALF_BEGIN_NUM + count % ALF_MAX_NUM)
        count += 1
         
        if not os.path.isdir(dir) :
            os.mkdir(dir)
               
        plt.figure(figsize=(16,16))
        step = np.random.choice([-1,1],500)
        arr = np.cumsum(step)
        plt.plot(arr)
        plt.show()
 
        plt.savefig(dir + PATH_DELIMITER + company_name)
 
# 前処理
def preprocess(var_amount=4) :
    for dir in LABEL_NAME :
        num = 0
        arrlist = []
        files = glob.glob(DIR_PATH + PATH_DELIMITER + dir + "/*.png")
 
        for imgfile in files:
            img = load_img(imgfile, target_size=(IMAGE_HEIGHT, IMAGE_WIDTH))    # 画像ファイルの読み込み
            array = img_to_array(img) / 255                                     # 画像ファイルのnumpy化
            arrlist.append(array)                 # numpy型データをリストに追加
            for i in range(var_amount-1):
                arr2 = array
                arr2 = random_rotation(arr2, rg=90)
                arrlist.append(arr2)              # numpy型データをリストに追加
            num += 1
 
        nplist = np.array(arrlist)
        np.save(dir + NPY_EXTENSION_NAME, nplist)
        print(">> " + dir + "から" + str(num) + "個のファイル読み込み成功")
 
# 学習
def lerning(tsnum=30, nb_epoch=50, batch_size=8, learn_schedule=0.9):
    X_TRAIN_list = []; Y_TRAIN_list = []; X_TEST_list = []; Y_TEST_list = [];
    target = 0
    for filename in LABEL_NAME :
        data = np.load(filename + NPY_EXTENSION_NAME)
        trnum = data.shape[0] - tsnum
        X_TRAIN_list += [data[i] for i in range(trnum)]
        Y_TRAIN_list += [target] * trnum
        X_TEST_list  += [data[i] for i in range(trnum, trnum+tsnum)]
        Y_TEST_list  += [target] * tsnum;
        target += 1
 
    X_TRAIN = np.array(X_TRAIN_list + X_TEST_list)    # 連結
    Y_TRAIN = np.array(Y_TRAIN_list + Y_TEST_list)    # 連結
    print(">> 学習サンプル数 : ", X_TRAIN.shape)
    y_train = np_utils.to_categorical(Y_TRAIN, target)    # 自然数をベクトルに変換
    valrate = tsnum * target * 1.0 / X_TRAIN.shape[0]
 
    # 学習率の変更
    class Schedule(object):
        def __init__(self, init=0.001):      # 初期値定義
            self.init = init
        def __call__(self, epoch):           # 現在値計算
            lr = self.init
            for i in range(1, epoch+1):
                lr *= learn_schedule
            return lr
 
    def get_schedule_func(init):
        return Schedule(init)
 
    lrs = LearningRateScheduler(get_schedule_func(0.001))
    mcp = ModelCheckpoint(filepath='best.hdf5', monitor='val_loss', verbose=1, save_best_only=True, mode='auto')
     
    # create model
    ipshape=(X_TRAIN.shape[1], X_TRAIN.shape[2], X_TRAIN.shape[3])
    num_classes=target
 
    model = Sequential()
 
    model.add(Conv2D(24, 3, padding='same', input_shape=ipshape))
    model.add(Activation('relu'))
 
    model.add(Conv2D(48, 3))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.5))
 
    model.add(Conv2D(96, 3, padding='same'))
    model.add(Activation('relu'))
 
    model.add(Conv2D(96, 3))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.5))
 
    model.add(Flatten())
    model.add(Dense(128))
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
 
    model.add(Dense(num_classes))
    model.add(Activation('softmax'))
 
    adam = Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
    model.compile(loss='categorical_crossentropy',
                  optimizer=adam,
                  metrics=['accuracy'])
 
    print(">> 学習開始")
    hist = model.fit(X_TRAIN, y_train,
                     batch_size=batch_size,
                     verbose=1,
                     epochs=nb_epoch,
                     validation_split=valrate,
                     callbacks=[lrs, mcp])
 
    json_string = model.to_json()
    json_string += '##########' + str(LABEL_NAME)
    open('model.json', 'w').write(json_string)
    model.save_weights('last.hdf5')
 
 
# TEST
def test_process(imgname):
    modelname_text = open("model.json").read()
    json_strings = modelname_text.split('##########')
    textlist = json_strings[1].replace("[", "").replace("]", "").replace("\'", "").split()
    model = model_from_json(json_strings[0])
    model.load_weights("last.hdf5")  # best.hdf5 で損失最小のパラメータを使用
    img = load_img(imgname, target_size=(IMAGE_HEIGHT, IMAGE_WIDTH))   
    TEST = img_to_array(img) / 255
 
    pred = model.predict(np.array([TEST]), batch_size=1, verbose=0)
     
    return str(pred), textlist[np.argmax(pred)].replace(",", "")
ランダムウォークしたチャートを作成

実際の株式市場のチャートを使用するのはやっぱり面倒くさかったので、ランダムウォークな株価チャートを作って架空の会社のチャートを作ってみました。

Pythonインタラクティブ・モードで実行して以下を打ちましょう。 f:id:monex_engineer:20190711134414p:plain

それぞれteachフォルダに教師データを100枚、testフォルダにテストデータを50枚用意しました。 f:id:monex_engineer:20190711134532p:plain

100枚! f:id:monex_engineer:20190711134558p:plain

50枚! f:id:monex_engineer:20190711134640p:plain

今回の分類は以下の4パターンに分けて分類してみました。

チャートの見た目が「逆U字型、 右下がり型、右上がり型、V字型」のものです。

ラベル付は手作業でやりました。
誰か自動化してくれー。

前処理開始!

f:id:monex_engineer:20190711134748p:plain 無事終わりました!

学習

f:id:monex_engineer:20190711134827p:plain 学習できました。

テスト!

今回は以下の画像とそっくりな画像を取ってこれるかテストします。 f:id:monex_engineer:20190711134903p:plain

以下のソースコードで実行しました。

#!/usr/bin/env python
# coding: utf-8
 
import os
import os.path as op
import glob
import keras_chart_cnn as kcc
 
PATH_DELIMITER = os.sep # パス区切り文字
img_class_list = []
same_class_list = []
 
if __name__ == "__main__" :
    test_img_list = glob.glob("." + PATH_DELIMITER + "test" + PATH_DELIMITER + "*.png")
 
    for test_img in test_img_list :
        ret = kcc.test_process(test_img)
        ret += (test_img,)
        img_class_list.append(ret)
        print("===============================================================================================================")
        print(ret)
        print("===============================================================================================================")
 
    tgt_img_path = input("\n>> input : ")
    while (True) :
        if op.isfile(tgt_img_path) :
            break
        else :
            print(">> そのファイルは存在しません!")
            tgt_img_path = input("\n>> input : ")
     
    tgt_ret = kcc.test_process(tgt_img_path)
 
    for img_class in img_class_list :
        class_name = img_class[1]
        class_file_path = img_class[2]
        tgt_class_name = tgt_ret[1]
 
        if class_name == tgt_class_name :
            if op.basename(class_file_path) != op.basename(tgt_img_path) :
                same_class_list.append(class_file_path)
 
    print("**********************************************************************************************************")
    for same_file in same_class_list :
        print(same_file)
    print("**********************************************************************************************************")
結果発表~

以下のような結果が出ました。

"*"で囲まれた画像のパスがそっくりなチャートだとAI君は言っています。
f:id:monex_engineer:20190711135034p:plain

実際の画像を見てみましょう。
f:id:monex_engineer:20190711135102p:plain

う~ん。似ているのか?
けど、全く違うものは選ばれてないと思う!
微妙な感じになってしまった…

感想

①教師データの数やラベル付の種類を増やしたらもっと精度はあがるはず!
イノベーションが起きたかはわからない。

以上、ありがとうございました。

諸 大樹システム開発部 開発グループ エンジニア