見出し画像

マガジン「EXCELでFX(外国為替)取引を楽しむ」で使ったマクロ(VBA)一覧

記事ではデータを使って一部しか検証していません。他にいろいろ試してみたい人のために記事で使ったエクセル用マクロ(VBA)や計算式をまとめてあります。

動作確認はOffice2019のエクセル上で行っています。また、検証しながらのコードなのできれいに整理されていない部分もあります。

グラフ化は基本、手動でその都度、完成していますが一部自動でグラフ化したマクロコードもあります。

マクロ付きエクセルファイルの供給は不安に思う方も多いので、コードとしてコピーしてマクロファイルを作成してください。

(参考) 新規のマクロファイル作成はメニューから

[開発]→左側にある[マクロ]→マクロ名を記入して[開始]をクリック

でマクロファイルが開きます。メニューに[開発]ボタンが表示されていない場合は

[ファイル]→[オプション]→[リボンのユーザー設定]→[開発]にチェック

で表示されるようになります。

■相関係数を使って為替相場見通しを予測してみた

A列 A1~ 基準データ
B列 B1~ 比較する全データ(基準データよりは多くなる)
C列 C1~ 相関係数の計算結果を出力

Sub CORR_SCAN()

     Dim X, Y, NUM1, NUM2, N As Variant
     Columns(3).Clear
     
'データ個数検出(A列,B列)
     NUM1 = Cells(1, 1).End(xlDown).Row
     NUM2 = Cells(1, 2).End(xlDown).Row
         
'ワークシート関数で相関曲線を計算しC列に出力
     For i = 1 To (NUM2 - NUM1)
        X = Range(Cells(1, 1), Cells(NUM1, 1))
        Y = Range(Cells(i, 2), Cells(i + NUM1 - 1, 2))
     Cells(i, 3) = WorksheetFunction.Correl(X, Y)
     Next i

     Cells(1.1).Select

End Sub

上記の計算結果をE列~H列にその都度、数値でコピーし、J列にアルゴリズムの判断式を挿入しておく

D1セル 足切りの基準値(1未満)
E列 E1~ 1週間分の相関係数
F列 F1~ 2週間分の相関係数
G列 G1~ 3週間分の相関係数
H列 H1~ 4週間分の相関係数
J列 J1~ 以下の計算式を挿入

=IF(MIN(E1:H1)<D$1,0,E1*F1*G1*H1)

使い方はD1セルの値を例えば「0.1」ステップずつ減少することにより相関関係が高い位置が抽出できます。

■多項式近似で為替相場見通しを予測してみた

近似式として3~6次までの「多項式近似」をマクロで書いていますが、一部変更することによりいろいろな近似式同士も比較することができます。

通常、マクロ設定ではグラフは手動設定で作図しませんが、ここではグラフが自動で出力されます。

xlPolynomial(多項式近似)
xlexponential(指数近似)
xllinear(線形近似)
xllogarithmic(対数近似)
xlmovingavg(移動平均)
xlpower(累乗近似)

A列 A1~ 近似式を求めるためのデータ

Sub Polynomial()

    Dim NUM  As Integer

'A列のデータ数を検出し分散図を選択
    NUM = Cells(1, 1).End(xlDown).Row
    ActiveSheet.Shapes.AddChart2(240, xlXYScatterSmooth).Select
    ActiveChart.SetSourceData Source:=Range(Cells(1, 1), Cells(NUM, 1))
    
    ActiveChart.FullSeriesCollection(1).Trendlines.Add
    
'近似式1
    ActiveChart.FullSeriesCollection(1).Trendlines(1).Select
    Selection.Format.Line.ForeColor.RGB = RGB(255, 0, 0)
    With Selection
        .Type = xlPolynomial
        .Order = 3
    End With
    Selection.Backward = 5
    
'近似式2
    ActiveChart.FullSeriesCollection(1).Trendlines.Add
    ActiveChart.FullSeriesCollection(1).Trendlines(2).Select
    Selection.Format.Line.ForeColor.RGB = RGB(0, 255, 0)
    With Selection
        .Type = xlPolynomial
        .Order = 4
    End With
    Selection.Backward = 5

'近似式3
    ActiveChart.FullSeriesCollection(1).Trendlines.Add
    ActiveChart.FullSeriesCollection(1).Trendlines(3).Select
    Selection.Format.Line.ForeColor.RGB = RGB(0, 0, 255)
    With Selection
        .Type = xlPolynomial
        .Order = 5
    End With
    Selection.Backward = 5
    
'近似式4
    ActiveChart.FullSeriesCollection(1).Trendlines.Add
    ActiveChart.FullSeriesCollection(1).Trendlines(4).Select
    Selection.Format.Line.ForeColor.RGB = RGB(0, 0, 0)
    With Selection
        .Type = xlPolynomial
        .Order = 6
    End With
    Selection.Backward = 5
    
    ActiveChart.ChartTitle.Text = "多項式近似:3次(赤)4,次(緑),5次(青),6次(黒)"

    Cells(1,1).Select
    
End Sub

コード自体は変更がしやすいように近似式を4個そのまま、書いています。

近似式の場合、一般にはA列にxデータ、B列にyデータを記入しますが、為替の場合、時間なのであまり意味がありません。そこでxデータは省略しています。省略した場合、xデータは1,2,3・・・と言うように自動的に設定されます。

もし、xデータを省略しない場合は

A列 A1~ 数値データ(x)
B列 B1~ 数値データ(y)

として、コードを以下のように変更してください。

ActiveChart.SetSourceData Source:=Range(Cells(1, 1), Cells(NUM, 2))


■通貨ペアの相関を時間変数として評価してみる

最大通貨は9個までで、基準通貨と比較することができるのは8個にです。
通貨データは同数と言う前提で、通貨データ及び、通貨の種類の数は自動で検出します。

相関係数を計算するデータ長は最大データ数を1/4、2/4、3/4、4/4の長さでそれぞれ自動で計算します。例えばデータ長が100→(25、50、75、100)として計算します。

A列 A2~ 基準通貨データ、例えばUSD/JPY
B列~I列 B2~I2 比較する通貨データ
K列~R列 K2~R2 相関係数の計算結果
1行目 USD/JPYのように通貨名を記入

Sub Currency_Pair()

    Dim NUM, NUM1, NUM2 As Integer

'データ数、通貨の数を検出(最大通貨数は9個)

    Range(Columns(10), Columns(20)).Clear
    NUM1 = Cells(1, 2).End(xlDown).Row
    NUM2 = Cells(1, 2).End(xlToRight).Column
    
'相関係数を計算
    Range(Cells(1, 2), Cells(1, NUM2)).Copy
    Range(Cells(1, 11), Cells(1, 11 + NUM2)).PasteSpecial
    Application.CutCopyMode = False
    
    NUM1 = NUM1 - 1
    For j = 1 To 4
        If Int(NUM1 / 4) * j + 1 > NUM1 Then
            NUM = NUM1
            Cells(1 + j, 10) = NUM & "営業日"
        Else
            NUM = Int(NUM1 / 4) * j + 1
            Cells(1 + j, 10) = NUM - 1 & "営業日"
        End If
        
        For i = 2 To NUM2
            X = Range(Cells(2, 1), Cells(NUM, 1))
            Y = Range(Cells(2, i), Cells(NUM, i))
            Cells(1 + j, 9 + i) = WorksheetFunction.Correl(X, Y)
        Next i
    Next j
    
    Cells(1, 1).Select

End Sub

■平日の曜日による為替変動を過去データから推測してみる

A列 A2~ 日付データ
B列 B2~ 高値データ
C列 C2~ 安値データ
1行目 各列の項目名
H列~N列 計算結果

コードが長くなってしまったため、一部は表示されてませんがスクロールで確認できます。

Sub Week()

    Dim Ns, Ne, NUMNN, VH, VL As Integer
    Dim X(), Fri(2), Thu(2), Wen(2), Tue(2), Mon(2), LH(2, 5) As Integer



'最新の金曜日を検索
    For i = 2 To 5
        If WeekdayName(Weekday(Cells(i, 1)), True) = "金" Then
            Ns = i
        End If
    Next i
    
'何週間あるか計算(1週間は5営業日で構成)
    NUM = Cells(1, 2).End(xlDown).Row
    NUM = Int((NUM - (Ns - 1)) / 5)

        
'各週毎の高値、安値の曜日確定
    VH = 2  '高値の列番号
    VL = 3  '安値の列番号
    
    NN = NUM * 5
    ReDim X(2, NN)

     
    For j = 1 To NUM
        For i = 0 To 4
            If WorksheetFunction.Rank(Cells(Ns + i, VH), Range(Cells(Ns, VH), Cells(Ns + 4, VH)), 0) = 1 Then
                X(1, 1 + i + (j - 1) * 5) = 1
            Else
                X(1, 1 + i + (j - 1) * 5) = 0
            End If
            
            If WorksheetFunction.Rank(Cells(Ns + i, VL), Range(Cells(Ns, VL), Cells(Ns + 4, VL)), 1) = 1 Then
                X(2, 1 + i + (j - 1) * 5) = 1
            Else
                X(2, 1 + i + (j - 1) * 5) = 0
            End If
            
        Next i
        Ns = Ns + 5
    Next j
    
'曜日毎の初期化と集計
    For i = 1 To 2
        Fri(i) = 0
        Thu(i) = 0
        Wen(i) = 0
        Tue(i) = 0
        Mon(i) = 0
    Next i

    For j = 1 To 2
        For i = 0 To NUM - 1
            Fri(j) = Fri(j) + X(j, 1 + 5 * i)
            Thu(j) = Thu(j) + X(j, 2 + 5 * i)
            Wen(j) = Wen(j) + X(j, 3 + 5 * i)
            Tue(j) = Tue(j) + X(j, 4 + 5 * i)
            Mon(j) = Mon(j) + X(j, 5 + 5 * i)
        Next i
    Next j
    
'結果出力
    Range(Columns(5), Columns(15)).Clear '出力画面をクリア

    Cells(1, 9) = "高値"
    Cells(1, 10) = "安値"
    Cells(2, 8) = "金曜"
    Cells(3, 8) = "木曜"
    Cells(4, 8) = "水曜"
    Cells(5, 8) = "火曜"
    Cells(6, 8) = "月曜"
    
    Cells(2, 9) = Fri(1)
    Cells(3, 9) = Thu(1)
    Cells(4, 9) = Wen(1)
    Cells(5, 9) = Tue(1)
    Cells(6, 9) = Mon(1)
    Cells(2, 10) = Fri(2)
    Cells(3, 10) = Thu(2)
    Cells(4, 10) = Wen(2)
    Cells(5, 10) = Tue(2)
    Cells(6, 10) = Mon(2)

'金曜日が最高値
    Erase LH
    
    For i = 0 To NUM - 1
        If X(2, 1 + 5 * i) > 0 And X(1, 1 + 5 * i) > 0 Then
            LH(1, 1) = LH(1, 1) + 1
        ElseIf X(2, 2 + 5 * i) > 0 And X(1, 1 + 5 * i) > 0 Then
            LH(1, 2) = LH(1, 2) + 1
        ElseIf X(2, 3 + 5 * i) > 0 And X(1, 1 + 5 * i) > 0 Then
            LH(1, 3) = LH(1, 3) + 1
        ElseIf X(2, 4 + 5 * i) > 0 And X(1, 1 + 5 * i) > 0 Then
            LH(1, 4) = LH(1, 4) + 1
        ElseIf X(2, 5 + 5 * i) > 0 And X(1, 1 + 5 * i) > 0 Then
            LH(1, 5) = LH(1, 5) + 1
        Else
        End If
    Next i
    
'木曜日が最高値
    For i = 0 To NUM - 1
        If X(2, 2 + 5 * i) > 0 And X(1, 2 + 5 * i) > 0 Then
            LH(2, 2) = LH(2, 2) + 1
        ElseIf X(2, 3 + 5 * i) > 0 And X(1, 2 + 5 * i) > 0 Then
            LH(2, 3) = LH(2, 3) + 1
        ElseIf X(2, 4 + 5 * i) > 0 And X(1, 2 + 5 * i) > 0 Then
            LH(2, 4) = LH(2, 4) + 1
        ElseIf X(2, 5 + 5 * i) > 0 And X(1, 2 + 5 * i) > 0 Then
            LH(2, 5) = LH(2, 5) + 1
        Else
        End If
    Next i

'結果出力
    Cells(1, 13) = "最高値(金曜)"
    Cells(1, 14) = "最高値(木曜)"
    Cells(2, 12) = "金曜"
    Cells(3, 12) = "木曜"
    Cells(4, 12) = "水曜"
    Cells(5, 12) = "火曜"
    Cells(6, 12) = "月曜"
    Cells(8, 12) = "全体週の数"
    
    Cells(2, 13) = LH(1, 1)
    Cells(3, 13) = LH(1, 2)
    Cells(4, 13) = LH(1, 3)
    Cells(5, 13) = LH(1, 4)
    Cells(6, 13) = LH(1, 5)
    Cells(3, 14) = LH(2, 2)
    Cells(4, 14) = LH(2, 3)
    Cells(5, 14) = LH(2, 4)
    Cells(6, 14) = LH(2, 5)

    Cells(1, 1).Select
    
End Sub

■急落相場の戻り値をドル円相場で確認してみる

A列 A2~ 日付データ
B列 B2~ 始値データ
C列 C2~ 高値データ
D列 D2~ 終値データ
1行目 A1~D1 各列の項目名

変数 Vdown 急落条件(円)
変数 A 何日後のデータ比較

H1列~J7列 データ出力エリア

Sub Half_retrun()

    Dim NUM, Vdown, A As Single
    Dim X(), Y(), Sx(5), Sy(5) As Single
    
    NUM = Cells(1, 1).End(xlDown).Row
    ReDim X(5, NUM)
    ReDim Y(5, NUM)
    Erase Sx
    Erase Sy

    Vdown = 1.5           '下落金額
    V33 = 1 / 3    '戻り率 1/3   33%
    V50 = 1 / 2    '戻り率 1/2   50%
    V66 = 2 / 3    '戻り率 2/3   66%
    V100 = 1 / 1   '戻り率 1/1  100%
    
    Range(Columns(8), Columns(10)).Clear

    A = 3          '「A」日後の比較


'分類条件は下落金額
    For i = 2 + A To NUM
        If Cells(i, 2) - Cells(i, 4) > Vdown Then
        
'同日の始値と安値の差と戻り率で判断
            If Cells(i, 5) - Cells(i, 4) > (Cells(i, 2) - Cells(i, 4)) * V66 Then
                X(1, i) = 1
            ElseIf Cells(i, 5) - Cells(i, 4) > (Cells(i, 2) - Cells(i, 4)) * V50 Then
                X(2, i) = 1
            ElseIf Cells(i, 5) - Cells(i, 4) > (Cells(i, 2) - Cells(i, 4)) * V33 Then
                X(3, i) = 1
            Else
                X(4, i) = 1
            End If

'{A}日後の高値と安値の差と戻り率で判断
            If Cells(i - A, 3) - Cells(i, 4) >= (Cells(i, 2) - Cells(i, 4)) * V66 Then
                Y(1, i) = 1
            ElseIf Cells(i - A, 3) - Cells(i, 4) >= (Cells(i, 2) - Cells(i, 4)) * V50 Then
                Y(2, i) = 1
            ElseIf Cells(i - A, 3) - Cells(i, 4) >= (Cells(i, 2) - Cells(i, 4)) * V33 Then
                Y(3, i) = 1
            Else
                Y(4, i) = 1
            End If
        Else
        End If

    Next i
    
'結果集計
    For i = 1 + A To NUM
        For j = 1 To 5
            Sx(j) = Sx(j) + X(j, i)
            Sy(j) = Sy(j) + Y(j, i)
        Next j
    Next i
    
    For i = 1 To 4
       Cells(i + 1, 9) = Sx(i)
       Cells(i + 1, 10) = Sy(i)
    Next i
    
    Cells(6, 9) = Sx(1) + Sx(2) + Sx(3) + Sx(4)
    Cells(6, 10) = Sy(1) + Sy(2) + Sy(3) + Sy(4)
    
    Cells(2, 8) = "66以上%"
    Cells(3, 8) = "50~65%"
    Cells(4, 8) = "33~49%"
    Cells(5, 8) = "33%未満"
    Cells(6, 8) = "合計日数"
    Cells(7, 8) = "下落金額(" & Vdown & "円以上)"
    Cells(1, 9) = "同日"
    Cells(1, 10) = A & "日後"
    
    
Cells(1, 1).Select

End Sub

■為替相場の変動を周波数分析してみると周期性は見えてくるか

A列 A1~ 日付データ
B列 B2~ 繰り返し回数
C列 C1~ 発生確率の平均
D列 D2~ 1回目の発生確率(最新)
E列 E2~  2回目の発生確率
・・・・・・・

FFT計算結果が出力されるD列以降の最後の行をk番とすると「k+2」行に
FFT複素出力、n=1の偏角(位相)が表示されます。

FFTの特性上、Nfftの数値は4,8、16、32、64、128・・・・と言う数値を設定してください。

Sub FX_FFT_new()
'
    Dim F() As String
    Dim Nfft, Nscan, Nsum、N1, NUM As Double
     
'ワークシート関数名の短縮化
    Dim Fx As WorksheetFunction: Set Fx = WorksheetFunction
    Dim Ax As Worksheet: Set Ax = ActiveSheet
    
'初期設定
    NUM = Cells(1, 1).End(xlDown).Row  '使用最大データ数の確認
    Nfft = 32
    'FFTのポイント数(評価期間:営業日の日数)
    N1 = Int(NUM / Nfft)               '
    
    ReDim F(Nfft)        '
    Nscan = Nfft / 2                   '50%オーバーラップ(固定)
    

'ワークシート関数でFFT演算
    Range(Cells(1, 2), Cells(4096, 4096)).Clear
    For i = 1 To 2 * N1 - 1
        Application.Run "ATPVBAEN.XLAM!Fourier", Ax.Range(Cells(1 + Nscan * (i - 1), 1), Cells(1 + Nscan * (i - 1) + Nfft - 1, 1)), Ax.Cells(1, i + 3), False, False
    Next i

    Range(Cells(Nscan + 1, 2), Cells(4096, 4096)).Clear

'n=1の位相を計算(解像度は10度単位になるように四捨五入)
    For j = 1 To 2 * N1 - 1
             Cells(Nscan + 2, j + 3) = Fx.Round((Fx.ImArgument(Cells(2, j + 3)) / Fx.Pi() * 180 + 360) Mod 360, -1)
    Next j
    
'周波数の絶対値計算
    For j = 1 To 2 * N1 - 1
        For i = 1 To Nscan
            Cells(i, j + 3) = Fx.ImAbs(Cells(i, j + 3))
        Next i
    Next j
    
'発生確率に変換
    For j = 1 To 2 * N1 - 1
        Nsum = Fx.Sum(Range(Cells(2, j + 3), Cells(Nscan, j + 3)))
        Cells(1, j + 3) = Str(1 + Nscan * (j - 1))
        For i = 2 To Nscan
            Cells(i, j + 3) = Cells(i, j + 3) / Nsum
        Next i
    Next j

    
'周波数毎の平均化

    Columns(3).Font.Bold = True
    Cells(1, 3) = "平均 "
        
    For i = 2 To Nscan
        Cells(i, 3) = Fx.Average(Range(Cells(i, 4), Cells(i, 4 + 2 * N1 - 2)))
    Next i


'繰り返し回数を表示
    For i = 2 To Nscan
        Cells(i, 2) = i - 1
    Next i
    
    
'’処理に時間がかかるのでスペクトログラムをしたい場合は以下のコメント分をコードに変換してください
'’但し、十分に検証していないのと処理時間がフリーズしたように数十秒も掛かります。
'
''********  Spectrogram表示 *************
'
''グラフの削除
'    With ActiveSheet
'        For i = .ChartObjects.Count To 1 Step -1
'            If .ChartObjects(i).Chart.ChartTitle.Text = "Spectrogram_STFT" Then
'                .ChartObjects(i).Delete
'            End If
'        Next i
'    End With
'
''スペクトグラム軸、グラフ作業エリアを設定
'    Range(Cells(1, 4), Cells(1, 2 * N1 + 2)).Copy Destination:=Cells(Nscan + 4, 4)
'    Range(Cells(2, 2), Cells(Nscan, 2)).Copy Destination:=Cells(Nscan + 5, 3)
'    Range(Cells(Nscan + 5, 4), Cells(2 * Nscan + 3, 2 * N1 + 2)) = 1
'
''グラフ作画
'    Range(Cells(Nscan + 4, 3), Cells(2 * Nscan + 3, 2 * N1 + 2)).Select
'    ActiveSheet.Shapes.AddChart2(297, xlColumnStacked).Select
'    ActiveChart.SetSourceData Source:=Range(Cells(Nscan + 4, 3), Cells(2 * Nscan + 3, 2 * N1 + 2))
'    ActiveChart.ChartTitle.Text = "Spectrogram_STFT"
'    ActiveChart.ChartGroups(1).GapWidth = 0
'
'    For j = 1 To 2 * N1 - 1
'        For i = 2 To Nscan
'
'            ActiveChart.FullSeriesCollection(i - 1).Points(j).Select
'            Call RGBcolor(Cells(i, j + 3), R, G, B)
'
'            With Selection.Format.Fill
'                .Visible = msoTrue
'                .ForeColor.RGB = RGB(R, G, B)
'                .Transparency = 0
'                .Solid
'            End With
'
'        Next i
'    Next j
'
'    ActiveChart.Legend.Select
'    Selection.Delete
'
'    ActiveChart.Axes(xlValue).Select
'    Selection.Delete
'
''********************************************

    Cells(1, 1).Select


End Sub

スペクトログラム表示をする場合は以下のファンクションをVBAで上記マクロの後に貼り付けてください。

Function RGBcolor(ByVal x, ByRef R, ByRef G, ByRef B)
    N = 60
    
    If x < 1 / N Then
        R = 0
        G = 0
        B = 255
    ElseIf x < 2 / N Then
        R = 0
        G = 51
        B = 255
    ElseIf x < 3 / N Then
        R = 0
        G = 102
        B = 255
    ElseIf x < 4 / N Then
        R = 0
        G = 153
        B = 255
    ElseIf x < 5 / N Then
        R = 0
        G = 204
        B = 255
    ElseIf x < 6 / N Then
        R = 0
        G = 255
        B = 255
    ElseIf x < 6 / N Then
        R = 0
        G = 255
        B = 204
    ElseIf x < 7 / N Then
        R = 0
        G = 255
        B = 204
    ElseIf x < 8 / N Then
        R = 0
        G = 255
        B = 153
    ElseIf x < 9 / N Then
        R = 0
        G = 255
        B = 102
    ElseIf x < 10 / N Then
        R = 0
        G = 255
        B = 51
    ElseIf x < 11 / N Then
        R = 0
        G = 255
        B = 0
    ElseIf x < 12 / N Then
        R = 51
        G = 255
        B = 0
    ElseIf x < 13 / N Then
        R = 102
        G = 255
        B = 0
    ElseIf x < 14 / N Then
        R = 153
        G = 255
        B = 0
    ElseIf x < 15 / N Then
        R = 204
        G = 255
        B = 0
    ElseIf x < 16 / N Then
        R = 255
        G = 255
        B = 0
    ElseIf x < 17 / N Then
        R = 255
        G = 204
        B = 0
    ElseIf x < 18 / N Then
        R = 255
        G = 153
        B = 0
    ElseIf x < 19 / N Then
        R = 255
        G = 102
        B = 0
    Else
        R = 255
        G = 0
        B = 0
    End If
                                                                     
        
End Function

いいなと思ったら応援しよう!

tonto_bb
最後まで読んでいただいて有難うございます。 コメントは今後の参考に、フォローやサポートは今後の励みになります。