株価データなどの CSV データを加工するのに便利なツールとテクニック Windows で動かしています

2025年1月10日

sed

ストリーミングエディターで行ごとに文字列を加工

sed.exe -e  "/^$/d" -e "/^ $/d" -e "s/(\([0-9A-Z]\+\))/,\1.T,/g" -e "s/,//g" -e "s/\t/,/g"  -e "s/$/,,,,,,,,,,/g"  -e "s/^,*//g" -e "s/$/\r/g" 

  1. -e "/^$/d": 空行を削除します。
  2. -e "/^ $/d": スペースだけの行を削除します。
  3. -e "s/(\([0-9A-Z]\+\))/,\1.T,/g": ([0-9A-Z]+) パターンに一致する部分を ,[0-9A-Z].T, に置き換えます。
    • (\([0-9A-Z]\+\)): 括弧内に1つ以上の英数字(0-9, A-Z)に一致する部分を見つけます。
    • ,\1.T,: 一致する部分を ,[0-9A-Z].T, に変換します(\1 は一致する部分)。
  4. -e "s/,//g": すべてのカンマを削除します。
  5. -e "s/\t/,/g": タブをカンマに置き換えます。
  6. -e "s/$/,,,,,,,,,,/g": 各行の末尾に ,,,,,,,,,, を追加します。
  7. -e "s/^,*//g": 先頭のすべてのカンマを削除します。
  8. -e "s/$/\r/g": 各行の末尾にキャリッジリターン(改行)を追加します。
sed.exe -n "1p" y:\out.txt

1行目を表示します

sed.exe "s|/\([0-9]\)|/0\1|g; s|/0\([0-9]\{2\}\)|/\1|g"

このスクリプトは、標準の正規表現を使用して日付をフォーマットします。スクリプトの内容を部分ごとに解説します:

最初の部分

s|/\([0-9]\)|/0\1|g

この部分は、日付の月や日の前にゼロを追加します。具体的な正規表現の意味は次の通りです:

  • s| は置換コマンドの開始を示します。
  • / はスラッシュを検索対象に含めるための区切り文字です。
  • \([0-9]\) は、1桁の数字をキャプチャします。このキャプチャグループは、後で参照されます。
  • |/0\1| は置換後の文字列です。0\1 は、キャプチャグループ \([0-9]\) でキャプチャされた1桁の数字の前にゼロを追加します。
  • g はグローバルオプションで、行全体でこの置換を適用します。

次の部分

s|/0\([0-9]\{2\}\)|/\1|g

この部分は、誤って追加されたゼロを削除します。具体的な正規表現の意味は次の通りです:

  • s| は置換コマンドの開始を示します。
  • /0\([0-9]\{2\}\) は、ゼロに続く2桁の数字をキャプチャします。このキャプチャグループは、後で参照されます。
  • |/\1| は置換後の文字列です。/\1 はキャプチャグループ \([0-9]\{2\}\) でキャプチャされた2桁の数字を、そのままスラッシュ後に追加します。
  • g はグローバルオプションで、行全体でこの置換を適用します。

これで、日付の月や日の前に正しくゼロを追加しつつ、誤って追加されたゼロを削除できます。これにより、日付が 2024/3/1 のような形式から 2024/03/01 のように変換されます。

cut

指定した列を出力します

行末にカンマを複数追加した後このコマンドを使うことによってカンマの数を合わせることができます

cut -d "," -f 1-20,22 y:\output1.txt 

paste

2つのファイルを横につなげます

paste.exe  y:\t255t255.csv y:\tt252.csv 

awk

様々な条件や出力方法の指定が可能

awk -F, '{print $1, $3}' data.csv

縦の CSV を横の CSV に

C:\app\busybox\awk -F "," "NR==1{printf $1 \"",\"" $2; prev=$1; next} {if($1 != prev) {print \""\""; printf $1 \"",\"" $2} else {printf \"",\"" $2}; prev=$1} END{print \""\""}" y:/ticker1.csv > y:/t.csv

カラムの値を比較してカウントし、行の最後にそのカウント結果を追加

C:\app\busybox\awk -F "," "{count=0; for(i=3;i<=NF;i++) if ($i < $(i-1)) count++; print $0 \"",\"" count}" y:/t.csv > y:/t2.csv

trdsql

SQL が使えて便利です

数字の扱いにコツがあります

trdsql -ocrlf -is 1 "select c2 ,replace(c14, ' ', '') ,round(100*(CAST(c2 AS NUMERIC))/(CAST(c3 AS NUMERIC)),1)-100 from y:/t255.csv ORDER BY c13*1 DESC WHERE c2*1 > 100" >y:\ticker.csv

このコマンドは trdsql を使って、CSVファイル y:/t255.csv から指定された列を処理し、新しいCSVファイル y:\ticker.csv に出力するものです。詳細は以下の通りです:

  1. trdsql -ocrlf -is 1:
  • -ocrlf オプションは出力ファイルの行末がCRLF(Windowsスタイル)であることを指定します。
  • -is 1 オプションは、入力ファイルの1行目が列名を含むことを示します。
  1. SQL クエリ部分:
  • select c2 ,replace(c14, ' ', '') ,round(100*(CAST(c2 AS NUMERIC))/(CAST(c3 AS NUMERIC)),1)-100 from y:/t255.csv ORDER BY c13*1 DESC WHERE c2*1 > 100:
    • select c2, replace(c14, ' ', ''), round(100*(CAST(c2 AS NUMERIC))/(CAST(c3 AS NUMERIC)),1)-100
    • c2:第2列のデータを選択します。
    • replace(c14, ' ', ''):第14列のデータから空白を取り除いたものを選択します。
    • round(100*(CAST(c2 AS NUMERIC))/(CAST(c3 AS NUMERIC)),1)-100:第2列のデータを数値にキャストしてから、第3列のデータと除算し、その結果を100倍して1桁の精度で四捨五入し、さらに100を引いた値を選択します。
    • from y:/t255.csv:このクエリは y:/t255.csv ファイルに対して実行されます。
    • ORDER BY c13*1 DESC:第13列の数値データを降順で並べ替えます。
    • WHERE c2*1 > 100:第2列の数値データが100より大きい行のみを対象とします。
  1. 出力:
  • >y:\ticker.csv:クエリの結果を y:\ticker.csv ファイルに出力します。
trdsql.exe  "select c1 ,count(*)  from y:/ticker12.csv  group by  c1" >y:\tick.csv

  1. SQLクエリ部分:
  • select c1, count(*) from y:/ticker12.csv group by c1
    • select c1: 第1列のデータを選択します。
    • count(*): グループごとの行数をカウントします。
    • from y:/ticker12.csv: このクエリは y:/ticker12.csv ファイルに対して実行されます。
    • group by c1: 第1列の値ごとにデータをグループ化します。
  1. 出力:
  • >y:\tick.csv: クエリの結果を y:\tick.csv ファイルに出力します。

これにより、y:/ticker12.csv ファイルの第1列に基づいてデータをグループ化し、各グループの行数をカウントした結果が y:\tick.csv ファイルに保存されます。たとえば、もし y:/ticker12.csv に第1列が異なる値を持つデータが含まれている場合、その値ごとに行数がカウントされ、新しいCSVファイルに記録されます。

trdsql.exe "SELECT u.*,h.c2 FROM y:\ttt.csv as u LEFT JOIN y:/tick.csv as h ON(u.c1=h.c1) "  >y:\tic.csv

  1. SQLクエリ部分:
  • SELECT u.*,h.c2 FROM y:\ttt.csv as u LEFT JOIN y:/tick.csv as h ON(u.c1=h.c1)
    • SELECT u.*, h.c2: u テーブル(y:\ttt.csv の別名)からすべての列を選択し、さらに h テーブル(y:/tick.csv の別名)から第2列 (c2) を選択します。
    • FROM y:\ttt.csv as u: y:\ttt.csv ファイルを u という別名で使用します。
    • LEFT JOIN y:/tick.csv as h ON(u.c1=h.c1): y:/tick.csv ファイルを h という別名で使用し、u テーブルの c1 列と h テーブルの c1 列に基づいて左外部結合を行います。これは、u.c1h.c1 の値が一致する行を結合し、一致しない場合でも u テーブルの全行を保持します。
  1. 出力:
  • >y:\tic.csv: クエリの結果を y:\tic.csv ファイルに出力します。

これにより、y:\ttt.csv ファイルと y:/tick.csv ファイルのデータを結合し、結果を新しいCSVファイルに保存することができます。左外部結合を使用することで、y:\ttt.csv のすべての行が保持され、対応する y:/tick.csv のデータが追加されます。

trdsql.exe -is 1 "select c8 ,round(c6, 0),c1 from y:/ticker.csv ORDER BY c8,c1 DESC" >y:\ticker1.csv
  1. オプション:
  • -is 1: 入力ファイルの1行目が列名を含むことを示します。
  1. SQLクエリ部分:
  • select c8 ,round(c6, 0),c1 from y:/ticker.csv ORDER BY c8,c1 DESC
    • select c8, round(c6, 0), c1:
    • c8: 第8列のデータを選択します。
    • round(c6, 0): 第6列のデータを四捨五入して、整数に変換したものを選択します。
    • c1: 第1列のデータを選択します。
    • from y:/ticker.csv: このクエリは y:/ticker.csv ファイルに対して実行されます。
    • ORDER BY c8, c1 DESC: 第8列のデータを昇順で、次に第1列のデータを降順で並べ替えます。
  1. 出力:
  • >y:\ticker1.csv: クエリの結果を y:\ticker1.csv ファイルに出力します。

これにより、y:/ticker.csv ファイルの第8列、第6列を四捨五入した値、第1列のデータを選択し、指定された順序で並べ替えた結果が y:\ticker1.csv ファイルに保存されます。

縦に並んでいる株価データを銘柄ごとに横に並べるパッチファイル


setlocal enableDelayedExpansion

set inputFile="y:\ticker1.csv"
set outputFile="y:\t.csv"

:: 初期値を設定
set prevValue=
:: ファイル内の各行を読み込んで処理
(for /f "usebackq tokens=1,2 delims=," %%a in (%inputFile%) do (
    set "value1=%%a"
    set "value2=%%b"
    if "!value1!" neq "!prevValue!" (
        if "" neq "!prevValue!"    echo ,
        SET /P ="!value1!,!value2!" < NUL
    ) else (
        SET /P =",!value2!" < NUL
    )
    set "prevValue=!value1!"
)) > %outputFile%
echo , >> %outputFile%

このバッチスクリプトは、CSVファイル y:\ticker1.csv を読み込み、特定の列を処理して新しいCSVファイル y:\t.csv に保存するものです。詳細な説明を以下に示します:

  1. 初期設定:
  • setlocal enableDelayedExpansion:遅延環境変数展開を有効にします。これはループ内で変数を正しく展開するために必要です。
  • set inputFile="y:\ticker1.csv":入力ファイルとして y:\ticker1.csv を指定します。
  • set outputFile="y:\t.csv":出力ファイルとして y:\t.csv を指定します。
  1. 初期値の設定:
  • set prevValue=:前の値を保存する変数 prevValue を初期化します。
  1. ファイル内の各行を処理:
  • for /f "usebackq tokens=1,2 delims=," %%a in (%inputFile%) do
    • usebackq:入力ファイルのパスをバッククォートで囲むことを許可します。
    • tokens=1,2:カンマで区切られた各行の1番目と2番目のフィールドを変数 %%a%%b に格納します。
    • delims=,:フィールド区切り文字をカンマに設定します。
  1. 行ごとの処理:
  • set "value1=%%a":変数 value1 に第1フィールドの値を設定します。
  • set "value2=%%b":変数 value2 に第2フィールドの値を設定します。
  • if "!value1!" neq "!prevValue!":現在の値 value1 が前の値 prevValue と異なる場合:
    • if "" neq "!prevValue!" echo ,:前の値が空でない場合、カンマを出力します。
    • SET /P ="!value1!,!value2!" < NUL:現在の値 value1value2 を出力ファイルに書き込みます(改行なし)。
  • else:現在の値 value1 が前の値 prevValue と同じ場合:
    • SET /P =",!value2!" < NUL:カンマと現在の値 value2 を出力ファイルに書き込みます(改行なし)。
  • set "prevValue=!value1!":現在の値 value1prevValue に更新します。
  1. 最後の行処理:
  • echo , >> %outputFile%:出力ファイルの最後にカンマを追加します。

株価上昇の回数を数えるバッチファイル


setlocal enabledelayedexpansion

:: 入力ファイルと出力ファイルのパス
set "input_file=y:\tt.csv"
set "output_file=y:\t2.csv"

:: 一時ファイルのパス
set "temp_file=y:\temp.csv"
@echo off

:: 既存の一時ファイルを削除
if exist "%temp_file%" del "%temp_file%"

:: CSVファイルの読み込みと処理
for /F "tokens=*" %%A in (%input_file%) do (
    set "line=%%A"
    set "count=0"
    set /A "i=0"

    :: 各列をカウント
    for %%B in (!line!) do (
        set /A i+=1
        if !i! GTR 2 (
            if !previous_value! GTR %%B (
                set /A count+=1
            )
        )
        set "previous_value=%%B"
    )

    :: 結果を一時ファイルに出力
    echo !line!,!count! >> %temp_file%
)

:: 出力ファイルに一時ファイルの内容をコピー
move /Y %temp_file% %output_file%

具体的なWindows バッチファイルサンプル

最新の13ヶ月分の株価データをZIP ファイルから 解凍して日付を加工した後に出来高が多いものだけ抽出する。縦のデータを横のデータにしてから株価が上昇している回数をカウントします。現在の株価が昔の株価に比べてどれだけの割合で上昇してるかを確認します。その後カウントの多い順に並び替えて名称マスターとマッチングして表示するプログラムです

エクセルなどに取り込んで加工確認してください

5000クラ566621141328918284106160206371408402

名称マスター

Code,Name

入力データ

Date,Code,Close,Volume

バッチファイル

@echo off
setlocal enabledelayedexpansion
del y:\t1.csv
set count=0
for /f "delims=;" %%f in ('dir /b /o-n C:\data\kabu\*.zip') do (
  echo %%f
"C:\app\7-ZipPortable\App\7-Zip64\7z.exe"   x -y -o"y:\kabu\" C:\data\kabu\%%f
"C:\app\busybox\sed.exe" "s|/\([0-9]\)|/0\1|g; s|/0\([0-9]\{2\}\)|/\1|g" y:\kabu\%%~nf.csv >y:\kabu\a%%~nf.csv
type y:\kabu\a%%~nf.csv >>y:\t1.csv
    set /a count+=1
    if !count! geq 13 (
        goto :endloop
    )
    if !count! leq 1 (
         "C:\app\Perl\trdsql.exe" "select c2  from y:\kabu\a%%~nf.csv " >y:\n.csv
timeout /t 5
    )
)

:endloop
endlocal

echo Loop finished after processing 13 files.
"C:\app\Perl\trdsql.exe" "select c2,c3 ,c4,c1, ROUND(avg(CAST(c4 AS NUMERIC)/1000) OVER(PARTITION BY c2)) from y:/t1.csv  ORDER BY c2 DESC  ,c1 DESC  " >y:\ticker1.csv
"C:\app\Perl\trdsql.exe" "select u.* from y:/ticker1.csv as u JOIN y:/n.csv as h ON(u.c1=h.c1) WHERE u.c5*1>100  " >y:\ticker2.csv
C:\app\busybox\awk -F "," "NR==1{printf $1 \"",\"" $2; prev=$1; next} {if($1 != prev) {print \""\""; printf $1 \"",\"" $2} else {printf \"",\"" $2}; prev=$1} END{print \""\""}" y:/ticker2.csv > y:/ticker0.csv
C:\app\busybox\awk -F "," "NR==1{print $1 \"",\"" $2; prev=$1; next} " y:/ticker1.csv
C:\app\busybox\sed -e "s/$/,,,,,,,,,,,,/g" y:\ticker0.csv>y:\ticker3.csv
C:\app\busybox\cut -d "," -f 1-14 y:\ticker3.csv>y:\ticker4.csv
C:\app\busybox\awk -F "," "{count=0; for(i=3;i<=NF;i++) if ($i*1.0 < $(i-1)) count++; print $0 \"",\"" count}" y:\ticker4.csv > y:\ticker5.csv
C:\app\busybox\awk -F "," "{count=0; for(i=3;i<=5;i++) {if ($i*1.0 < $(i-1)) count++;ww=100;if($i>0) ww=int($2/$i*100+0.5); if (ww< 90) count--; }print $0 \"",\"" count}" y:\ticker5.csv > y:\ticker6.csv
C:\app\busybox\awk -F "," "{printf $1 \"",\"" $2 ; count=0;for(i=3;i<=NF-2;i++){ww=0;if($i>0) ww=int($2/$i*100+0.5)-100;printf \"",\"" ww ;  if (ww> 50/(12/(i-2))) count++;} print \"",\"" $(NF-1) \"",\"" $NF \"",\"" count}" y:\ticker6.csv > y:\ticker7.csv

"C:\app\Perl\trdsql.exe" "SELECT u.*,h.c2 FROM y:\ticker7.csv as u LEFT JOIN y:/name.csv as h ON(u.c1=h.c1)  ORDER BY u.c15*1 DESC,u.c16*1 DESC,u.c17*1 DESC"  >y:\ticker8.csv
C:\app\busybox\sed -e "s/$/,,,,,,,,,,,,/g" y:\ticker8.csv>y:\ticker3.csv
C:\app\busybox\cut -d "," -f 1-24  y:\ticker3.csv >y:\ticker9.csv
trdsql -ocrlf "select c1, c18,c2,c15,c16,c17,c3,c4, c5,c6,c7, c8, c9, c10, c11, c12, c13, c14 from y:\ticker9.csv " >y:\ticker.csv

timeout /t 55&goto:eof

Linux のツールを Windows で使うのはコツが必要です

bat,

Posted by eightban