19日に更新してた

アフィリエイトはないよ

pandas で rolling 使って robust zscore とか

pandas で rolling を使って一定範囲の robust zscore を zscore と、株とか FX とかで出てくるボリンジャーバンドのグラフのロウソク足が線を超えているのを robust zscore を使ってそれっぽくしたの*1と一緒に計算してみると、

import numpy as np
import pandas as pd

def pd_robust_zscore(col_name,n):
    # col_name:pandas.DataFrame の列名 n:幅
    median = df[col_name].rolling(n).median()
    q3 = df[col_name].rolling(n).quantile(0.75)
    q1 = df[col_name].rolling(n).quantile(0.25)
    return (df[col_name] - median) / ((q3 - q1) / 1.3489)

def pd_zscore(col_name,n):
    # col_name:pandas.DataFrame の列名 n:幅
    return (df[col_name] - df[col_name].rolling(n).mean()) / df[col_name].rolling(n).std()

def pd_robust_zscore_2(col_name,col_name_hl,n):
    # col_name:終値などの基準になる pandas.DataFrame の列名
    # col_name_hl:高値、低値などの算出したい pandas.DataFrame の列名
    # n:幅
    median = df[col_name].rolling(n).median()
    q3 = df[col_name].rolling(n).quantile(0.75)
    q1 = df[col_name].rolling(n).quantile(0.25) 
    return (df[col_name_hl] - median) / ((q3 - q1) / 1.3489)

df = pd.DataFrame()
df['a'] = np.random.randint(400,450,100)
df['b'] = df['a'] + 5

df['zscore'] = pd_zscore('a',5)
df['rob'] = pd_robust_zscore('a',5)
df['rob_hl'] = pd_robust_zscore_2('a','b',5)

以下のような感じです。

	a	b	zscore	rob	rob_hl
0	438	443	NaN	NaN	NaN
1	403	408	NaN	NaN	NaN
2	429	434	NaN	NaN	NaN
3	404	409	NaN	NaN	NaN
4	424	429	0.283253	0.000000	0.269780
...	...	...	...	...	...
95	422	427	0.544404	1.252550	1.734300
96	413	418	-0.354044	0.000000	0.518808
97	421	426	0.964764	0.899267	1.461308
98	414	419	-0.324865	0.000000	0.843062
99	440	445	1.660556	3.203637	4.046700
100 rows × 5 columns

*1:zscore でやったほうがもっとそれっぽいです。しかし、自分で書いといてこういうのも何なんですが、いずれにしてもテクニカル売買のグラフ的には意味がありそうだけれど数学的な意味は?

win11 wsl2 で使える docker を簡単に入れる方法

結論から言うと、Windows 用の docker が wsl2 に対応しているので Windows 用の docker Desktop をインストールするだけでデフォルト設定のディストリビューション

docker -v

が通るようになります。*1

ネットである通りに入れてもサービスを動かしてもすぐ止まってしまって、

docker run hello-world

が sudo をつけても動かなくて困ったのですが、これだと問題なく行けました。GPUも通ります。

jupyter-notebook は

docker run -p 8888:8888 

の後ろにコンテナ指定して動かした上で、

jupyter-notebook --NotebookApp.token=''

で jupyter-notebook を起動してやると

win11 のブラウザから、http://localhost:8888/tree でアクセスできます。*2

*1:設定変えれば特定のディストリビューションで動くようになります。

*2:token ないのを紹介するのもどうかとは思うのですが、とりあえず。

python int 4桁でアンダーバーが入るように出力する

python で format を使って数値にアンダーバーを入れて整形して出力するとき、3桁だと読みにくかったので4桁のを適当に書きなぐってみた。

num=123456789
def four_digit(num:int,text="_")->str:
    return "".join([s if i%4!=0 else f"{s}{text}" for i,s in enumerate(list(str(int(num)))[::-1])][::-1]).rstrip(text)

print(four_digit(num))
print(four_digit(num,text=","))

>>1_2345_6789
>>1,2345,6789

いちおう、カンマにもできる。

Windows 上の python の timestamp

win11 上で jupyter notebook 使っています。

import sys
sys.version

'3.8.12 (default, Oct 12 2021, 03:01:40) [MSC v.1916 64 bit (AMD64)]'

unix time のはじめの方を色々といじってみたところ、

import datetime
datetime.datetime(1970, 1, 1, 0, 0, 0), datetime.datetime.fromtimestamp(0)

>>(datetime.datetime(1970, 1, 1, 0, 0), datetime.datetime(1970, 1, 1, 9, 0))

こんな感じです。ここまでは中の時計の JST に合わせてくれているのだろうなと思うのでいいのですが、

datetime.datetime(1970, 1, 1, 9, 0, 0).timestamp()

>>OSError: [Errno 22] Invalid argument

と出ます。wsl python3 だと 0.0 と返ってきます。*1

import datetime
for d in range(1,3):
    for h in range(24):
        try:
            print(datetime.datetime(1970,1,d,h).timestamp())
        except:
            print(f'1970/1/{d} {h}:00 error')

で調べてみると、

1970/1/1 0:00 error
1970/1/1 1:00 error
1970/1/1 2:00 error
1970/1/1 3:00 error
1970/1/1 4:00 error
1970/1/1 5:00 error
1970/1/1 6:00 error
1970/1/1 7:00 error
1970/1/1 8:00 error
1970/1/1 9:00 error
1970/1/1 10:00 error
1970/1/1 11:00 error
1970/1/1 12:00 error
1970/1/1 13:00 error
1970/1/1 14:00 error
1970/1/1 15:00 error
1970/1/1 16:00 error
1970/1/1 17:00 error
1970/1/1 18:00 error
1970/1/1 19:00 error
1970/1/1 20:00 error
1970/1/1 21:00 error
1970/1/1 22:00 error
1970/1/1 23:00 error
1970/1/2 0:00 error
1970/1/2 1:00 error
1970/1/2 2:00 error
1970/1/2 3:00 error
1970/1/2 4:00 error
1970/1/2 5:00 error
1970/1/2 6:00 error
1970/1/2 7:00 error
1970/1/2 8:00 error
86400.0
90000.0
93600.0
97200.0
100800.0
104400.0
108000.0
111600.0
115200.0
118800.0
122400.0
126000.0
129600.0
133200.0
136800.0

ですので、エラーが出なくなるのは 1970/1/2 の 9 時からです。マイクロセカンドまでは試してないのですが、1秒前まではだめでした。*2

個人的には現時点であまり不都合がないのですけれど、なんとなく試してみて気になったので。

Windowsでマイナス時間はエラーとあったのですが、なんで一日ずれるかなぁ。

*1:ちなみに wsl python3 で datetime.datetime(1970, 1, 1, 0, 0) だと -32400.0 と返ってきます。3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0]

*2:なので当然、datetime.datetime(1970, 1, 2).timestamp() もエラーです。3日からOK

ubuntu の ffmpeg

win11 から ffmpeg をつかうのに、コンパイルのオプションを考えなくても使いたいところで動いてくれたという単純な理由で wsl2 を経由しています。

これまで ubuntu-20.04 の素の ffmpeg version 4.2.7 を使っておりました。

試しに ubuntu-22.04 の素の ffmpeg version 4.4.2 を使ってみたら、某公営放送からのラジオ、オンデマンドにダウンロードエラーが出るようになったので、apt そのままで使う方は乗り換えの際にはご注意を。radiko は大丈夫。

どうも akamai に行っちゃって、vod-stream.nhk.jp に行っていない模様。面倒なので20.04を使う予定。

radiko の県別放送局リストと放送局のエリアリスト

radiko の番組表って取れないのかなと思って検索してみたら、

ststarfield.blog.fc2.com

こちらのサイトに記載されていました。

県単位の放送局リスト、県別番組表、放送局別番組表が取れるみたいですが、放送局の放送範囲がわからないので書いてみました。

import urllib
import xml.etree.ElementTree as ET
from collections import defaultdict

area_dic = defaultdict(list)

for num in range(1,48):
    req = urllib.request.Request(f'http://radiko.jp/v3/station/list/JP{num}.xml')

    with urllib.request.urlopen(req) as response:
        XmlData = response.read()
    root = ET.fromstring(XmlData)

    area_name=root.attrib['area_name'].split()[0]
    for i in range(len(root)):
        area_dic[area_name].append(root[i][0].text)
        
#prefecture = [k for k in area_dic.keys()]

station = sorted(list(set(sum([v for v in area_dic.values()],[]))))

station_dic = defaultdict(list)

for sta in station:
    for k,l in area_dic.items():
        if sta in l:
            station_dic[sta].append(k)
            
for k,v in station_dic.items():
    print(k,v)

で以下のような感じです。

802 ['SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA']
ABC ['SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA']
ABS ['AKITA']
AFB ['AOMORI']
AFM ['AKITA']
AIR-G ['HOKKAIDO']
ALPHA-STATION ['KYOTO', 'OSAKA']
BAYFM78 ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
BSN ['NIIGATA']
BSS ['TOTTORI', 'SHIMANE']
CBC ['GIFU', 'AICHI', 'MIE']
CCL ['SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA']
CRK ['SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA']
CROSSFM ['FUKUOKA']
CRT ['TOCHIGI']
DATEFM ['MIYAGI']
E-RADIO ['SHIGA']
FBC ['FUKUI']
FM-FUJI ['YAMANASHI']
FM-OKAYAMA ['OKAYAMA']
FM-SANIN ['TOTTORI', 'SHIMANE']
FM807 ['TOKUSHIMA']
FMAICHI ['GIFU', 'AICHI', 'MIE']
FMF ['FUKUSHIMA']
FMFUKUI ['FUKUI']
FMFUKUOKA ['FUKUOKA']
FMGIFU ['GIFU']
FMGUNMA ['GUNMA']
FMI ['IWATE']
FMJ ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
FMK ['KUMAMOTO']
FMKAGAWA ['KAGAWA']
FMMIE ['MIE']
FMN ['NAGANO']
FMNAGASAKI ['NAGASAKI']
FMNIIGATA ['NIIGATA']
FMO ['SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA']
FMS ['SAGA']
FMT ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
FMTOYAMA ['TOYAMA']
FMY ['YAMAGUCHI']
FM_OITA ['OITA']
FM_OKINAWA ['OKINAWA']
GBS ['GIFU', 'AICHI', 'MIE']
HBC ['HOKKAIDO']
HELLOFIVE ['ISHIKAWA']
HFM ['HIROSHIMA']
HI-SIX ['KOUCHI']
HOUSOU-DAIGAKU ['HOKKAIDO', 'AOMORI', 'IWATE', 'MIYAGI', 'AKITA', 'YAMAGATA', 'FUKUSHIMA', 'IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA', 'NIIGATA', 'TOYAMA', 'ISHIKAWA', 'FUKUI', 'YAMANASHI', 'NAGANO', 'GIFU', 'SHIZUOKA', 'AICHI', 'MIE', 'SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA', 'TOTTORI', 'SHIMANE', 'OKAYAMA', 'HIROSHIMA', 'YAMAGUCHI', 'TOKUSHIMA', 'KAGAWA', 'EHIME', 'KOUCHI', 'FUKUOKA', 'SAGA', 'NAGASAKI', 'KUMAMOTO', 'OITA', 'MIYAZAKI', 'KAGOSHIMA', 'OKINAWA']
IBC ['IWATE']
IBS ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
INT ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
JOAK ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA', 'NIIGATA', 'YAMANASHI', 'NAGANO']
JOAK-FM ['HOKKAIDO', 'AOMORI', 'IWATE', 'MIYAGI', 'AKITA', 'YAMAGATA', 'FUKUSHIMA', 'IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA', 'NIIGATA', 'TOYAMA', 'ISHIKAWA', 'FUKUI', 'YAMANASHI', 'NAGANO', 'GIFU', 'SHIZUOKA', 'AICHI', 'MIE', 'SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA', 'TOTTORI', 'SHIMANE', 'OKAYAMA', 'HIROSHIMA', 'YAMAGUCHI', 'TOKUSHIMA', 'KAGAWA', 'EHIME', 'KOUCHI', 'FUKUOKA', 'SAGA', 'NAGASAKI', 'KUMAMOTO', 'OITA', 'MIYAZAKI', 'KAGOSHIMA', 'OKINAWA']
JOBK ['SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA']
JOCK ['TOYAMA', 'ISHIKAWA', 'FUKUI', 'GIFU', 'SHIZUOKA', 'AICHI', 'MIE']
JOEU-FM ['EHIME']
JOFK ['TOTTORI', 'SHIMANE', 'OKAYAMA', 'HIROSHIMA', 'YAMAGUCHI']
JOHK ['AOMORI', 'IWATE', 'MIYAGI', 'AKITA', 'YAMAGATA', 'FUKUSHIMA']
JOIK ['HOKKAIDO']
JOLK ['FUKUOKA', 'SAGA', 'NAGASAKI', 'KUMAMOTO', 'OITA', 'MIYAZAKI', 'KAGOSHIMA', 'OKINAWA']
JORF ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
JOYFM ['MIYAZAKI']
JOZK ['TOKUSHIMA', 'KAGAWA', 'EHIME', 'KOUCHI']
JRT ['TOKUSHIMA']
K-MIX ['SHIZUOKA']
KBC ['FUKUOKA', 'SAGA']
KBS ['SHIGA', 'KYOTO', 'OSAKA']
KISSFMKOBE ['SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA']
KNB ['TOYAMA']
KRY ['YAMAGUCHI']
LFR ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
LOVEFM ['FUKUOKA']
MBC ['KAGOSHIMA']
MBS ['SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA']
MRO ['ISHIKAWA']
MRT ['MIYAZAKI']
MYUFM ['KAGOSHIMA']
NACK5 ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
NBC ['SAGA', 'NAGASAKI']
NORTHWAVE ['HOKKAIDO']
OBC ['SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA']
OBS ['OITA']
QRR ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
RAB ['AOMORI']
RADIOBERRY ['TOCHIGI']
RBC ['OKINAWA']
RCC ['HIROSHIMA']
RFC ['FUKUSHIMA']
RFM ['YAMAGATA']
RKB ['FUKUOKA', 'SAGA']
RKC ['KOUCHI']
RKK ['KUMAMOTO']
RN1 ['HOKKAIDO', 'AOMORI', 'IWATE', 'MIYAGI', 'AKITA', 'YAMAGATA', 'FUKUSHIMA', 'IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA', 'NIIGATA', 'TOYAMA', 'ISHIKAWA', 'FUKUI', 'YAMANASHI', 'NAGANO', 'GIFU', 'SHIZUOKA', 'AICHI', 'MIE', 'SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA', 'TOTTORI', 'SHIMANE', 'OKAYAMA', 'HIROSHIMA', 'YAMAGUCHI', 'TOKUSHIMA', 'KAGAWA', 'EHIME', 'KOUCHI', 'FUKUOKA', 'SAGA', 'NAGASAKI', 'KUMAMOTO', 'OITA', 'MIYAZAKI', 'KAGOSHIMA', 'OKINAWA']
RN2 ['HOKKAIDO', 'AOMORI', 'IWATE', 'MIYAGI', 'AKITA', 'YAMAGATA', 'FUKUSHIMA', 'IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA', 'NIIGATA', 'TOYAMA', 'ISHIKAWA', 'FUKUI', 'YAMANASHI', 'NAGANO', 'GIFU', 'SHIZUOKA', 'AICHI', 'MIE', 'SHIGA', 'KYOTO', 'OSAKA', 'HYOGO', 'NARA', 'WAKAYAMA', 'TOTTORI', 'SHIMANE', 'OKAYAMA', 'HIROSHIMA', 'YAMAGUCHI', 'TOKUSHIMA', 'KAGAWA', 'EHIME', 'KOUCHI', 'FUKUOKA', 'SAGA', 'NAGASAKI', 'KUMAMOTO', 'OITA', 'MIYAZAKI', 'KAGOSHIMA', 'OKINAWA']
RNB ['EHIME']
RNC ['KAGAWA']
ROK ['OKINAWA']
RSK ['OKAYAMA']
SBC ['NAGANO']
SBS ['SHIZUOKA']
STV ['HOKKAIDO']
TBC ['MIYAGI']
TBS ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
TOKAIRADIO ['GIFU', 'AICHI', 'MIE']
WBS ['WAKAYAMA']
YBC ['YAMAGATA']
YBS ['YAMANASHI']
YFM ['IBARAKI', 'TOCHIGI', 'GUNMA', 'SAITAMA', 'CHIBA', 'TOKYO', 'KANAGAWA']
ZIP-FM ['GIFU', 'AICHI', 'MIE']

結構、その県でしか聞けない放送局が多いと思った。

jupyter notebook で易占をできるようにしてみた。

コイン3枚法で作ってみました。

解説にリンクが欲しかったので、

tankyuu.net
1percent-better.com
ekikyo.net
ekikyou-dokugaku.com

の4サイトさんの爻辞へのリンクを作ってます。

こんな感じの表示になります。

import datetime
import random
import re
from IPython.display import HTML

random.seed()

# 本卦 爻
honka_raw = [[random.randint(0,1) for j in range(3)] for i in range(6)]

honka = [1 if sum(raw)>=2 else 0 for raw in honka_raw]

kou = [n for n, raw in enumerate(honka_raw) if sum(raw)==0 or sum(raw)==3 ]

# 之卦
sika = [abs(k-1) if n in kou else k for n,k in enumerate(honka) if len(kou)>0]

# 互卦
goka = honka[1:4] + honka[2:5]

# 賓卦
hinka = honka[::-1]

# 裏卦
rika = [abs(i-1) for i in honka]

ke_list = [['01', '43', '14', '34', '09', '05', '26', '11'],
          ['10', '58', '38', '54', '61', '60', '41', '19'],
          ['13', '49', '30', '55', '37', '63', '22', '36'],
          ['25', '17', '21', '51', '42', '03', '27', '24'],
          ['44', '28', '50', '32', '57', '48', '18', '46'],
          ['06', '47', '64', '40', '59', '29', '04', '07'],
          ['33', '31', '56', '62', '53', '39', '52', '15'],
          ['12', '45', '35', '16', '20', '08', '23', '02']]

ke_list2 = [['乾為天', '沢天夬', '火天大有', '雷天大壮', '風天小畜', '水天需', '山天大畜', '地天泰'],
          ['天沢履', '兌為沢', '火沢睽', '雷沢帰妹', '風沢中孚', '水沢節', '山沢損', '地沢臨'],
          ['天火同人', '沢火革', '離為火', '雷火豊', '風火家人', '水火既済', '山火賁', '地火明夷'],
          ['天雷无妄', '沢雷随', '火雷噬嗑', '震為雷', '風雷益', '水雷屯', '山雷頤', '地雷復'],
          ['天風姤', '沢風大過', '火風鼎', '雷風恒', '巽為風', '水風井', '山風蠱', '地風升'],
          ['天水訟', '沢水困', '火水未済', '雷水解', '風水渙', '坎為水', '山水蒙', '地水師'],
          ['天山遯', '沢山咸', '火山旅', '雷山小過', '風山漸', '水山蹇', '艮為山', '地山謙'],
          ['天地否', '沢地萃', '火地晋', '雷地豫', '風地観', '水地比', '山地剥', '坤為地']]

ke_list3 = ['keniten',
 'koniti',
 'suiraityun',
 'sansuimou',
 'suitenzyu',
 'tensuisyou',
 'tisuisi',
 'suitihi',
 'fuutensyoutiku',
 'tentakuri',
 'titentai',
 'tentihi',
 'tenkadouzin',
 'katentaiyuu',
 'tizanken',
 'raitiyo',
 'takuraizui',
 'sanpuuko',
 'titakurin',
 'fuutikan',
 'karaizeigou',
 'sankahi',
 'santihaku',
 'tiraifuku',
 'tenraimumou',
 'santentaitiku',
 'sanraii',
 'takufuutaika',
 'kanisui',
 'riika',
 'takuzankan',
 'raifuukou',
 'tenzanton',
 'raitentaisou',
 'katisin',
 'tikameii',
 'fuukakazin',
 'katakukei',
 'suizanken',
 'raisuikai',
 'santakuson',
 'fuuraieki',
 'takutenkai',
 'tenpuukou',
 'takutisui',
 'tifuusyou',
 'takusuikon',
 'suifuusei',
 'takkakaku',
 'kafuutei',
 'sinirai',
 'gonisan',
 'fuuzanzen',
 'raitakukimai',
 'raikahou',
 'kazanryo',
 'sonifuu',
 'daitaku',
 'fuusuikan',
 'suitakusetu',
 'fuutakutyuufu',
 'raizansyouka',
 'suikakisei',
 'kasuibisei']

ke_list4 = ['36_meii',
 '9_shouchiku',
 '5_ju',
 '33_ton',
 '62_shoka',
 '41_son',
 '8_hi',
 '29_kan',
 '26_taichiku',
 '16_yo',
 '19_rin',
 '54_kimai',
 '3_chun',
 '15_ken',
 '11_tai',
 '47_kon',
 '43_kai',
 '20_kan',
 '34_taiso',
 '28_taika',
 '7_shi',
 '40_kai',
 '61_chufu',
 '38_kei',
 '24_fuku',
 '46_shou',
 '39_ken',
 '6_shou',
 '44_kou',
 '45_sui',
 '50_tei',
 '60_setsu',
 '22_hi',
 '48_sei',
 '56_ryo',
 '42_eki',
 '2_kon',
 '25_mubo',
 '59_kan',
 '53_zen',
 '4_mou',
 '32_kou',
 '12_hi',
 '1_ken',
 '55_hou',
 '51_shin',
 '64_bisei',
 '17_zui',
 '14_taiyu',
 '13_doujin',
 '37_kajin',
 '21_zeigou',
 '58_da',
 '35_shin',
 '49_kaku',
 '57_son',
 '30_ri',
 '18_ko',
 '23_haku',
 '63_kisei',
 '27_i',
 '31_kan',
 '10_ri',
 '52_gon']

hatike=[[1, 1, 1],
         [1, 1, 0],
         [1, 0, 1],
         [1, 0, 0],
         [0, 1, 1],
         [0, 1, 0],
         [0, 0, 1],
         [0, 0, 0]]

hatike_list=[['乾', 'https://ekikyo.net/8ka/ken.html'],
             ['兌', 'https://ekikyo.net/8ka/da.html'],
             ['離', 'https://ekikyo.net/8ka/ri.html'],
             ['震', 'https://ekikyo.net/8ka/sin.html'],
             ['巽', 'https://ekikyo.net/8ka/son.html'],
             ['坎', 'https://ekikyo.net/8ka/kan.html'],
             ['艮', 'https://ekikyo.net/8ka/gon.html'],
             ['坤', 'https://ekikyo.net/8ka/kon.html']]

def hatikeHTML(list_in):
    return f'<a href="{hatike_list[hatike.index(list_in[:3])][1]}"target="_blank">{hatike_list[hatike.index(list_in[:3])][0]}</a>',f'<a href="{hatike_list[hatike.index(list_in[3:])][1]}"target="_blank">{hatike_list[hatike.index(list_in[3:])][0]}</a>'

def ekikyonet(list_in):
    return f'<a href="https://ekikyo.net/64ka/{ke_list[hatike.index(list_in[:3])][hatike.index(list_in[3:])]}.html"target="_blank">{ke_list2[hatike.index(list_in[:3])][hatike.index(list_in[3:])]}</a>'

def ekikyodokugaku(list_in,k1='',k2=''):
    return f'<a href="https://ekikyou-dokugaku.com/{ke_list3[int(ke_list[hatike.index(list_in[:3])][hatike.index(list_in[3:])])-1]}{k1}.html"target="_blank">{ke_list2[hatike.index(list_in[:3])][hatike.index(list_in[3:])]}{k2}</a>'

def tankyuunet(list_in):
    return f'<a href="https://tankyuu.net/eki/iching{int(ke_list[hatike.index(list_in[:3])][hatike.index(list_in[3:])])}.html"target="_blank">{ke_list2[hatike.index(list_in[:3])][hatike.index(list_in[3:])]}</a>'

def one_percent(list_in):
    list_out = ke_list[hatike.index(list_in[:3])][hatike.index(list_in[3:])]
    if list_out[0] == "0":
        list_out = list_out[1:]        
    for t in ke_list4:
        if re.match(list_out+"_",t):
            return f'<a href="https://1percent-better.com/oriental_wisdom/iching/hexagram/{t}/"target="_blank">{ke_list2[hatike.index(list_in[:3])][hatike.index(list_in[3:])]}</a>'
    

if len(kou)>0:
    koudic={0:'初',
           1:'二',
           2:'三',
           3:'四',
           4:'五',
           5:'上',}
    if len(kou)==1:
        kou_text=f' {koudic[kou[0]]}爻'
        kou4=kou[0]+1
    else:
        kou_text=''
        kou4=''
        
    kou3=''
    for s in kou:
        kou3 = kou3 + koudic.get(s) +" "
    sikaHTML=f'<tr><td>之卦</td>\
    <td>{tankyuunet(sika)}</td>\
    <td>{one_percent(sika)}</td>\
    <td>{ekikyonet(sika)}</td><td>{kou3}爻変</td>\
    <td>{ekikyodokugaku(sika)}</td>\
    <td>今後の状態</td>\
    <td>{hatikeHTML(sika)[1]}</td><td>{hatikeHTML(sika)[0]}</td></tr>'
    
else:
    kou=''
    kou_text=''
    sikaHTML=''
    kou4=''

sinreki=[str(s).zfill(2) for s in [19,11,34,43,1,44,33,12,20,23,2,24]]
kyuureki=(sinreki+sinreki)[1:13]
if ke_list[hatike.index(honka[:3])][hatike.index(honka[3:])] in sinreki:
    syousoku=f'新暦 {1+sinreki.index(ke_list[hatike.index(honka[:3])][hatike.index(honka[3:])])}月、旧暦 {1+kyuureki.index(ke_list[hatike.index(honka[:3])][hatike.index(honka[3:])])}月'
else:
    syousoku=''

def printhtml():
    display(HTML(f'<h3>{datetime.datetime.now()}</h3>\
    <h1>{naiyou}</h1>\
    <table>\
    <tr>\
    <td></td>\
    <td>tankyuu.net</td>\
    <td>1percent-better.com</td>\
    <td>ekikyo.net</td><td></td>\
    <td>ekikyou-dokugaku.com</td>\
    <td>{syousoku}</td>\
    <td>上爻</td><td>下爻</td>\
    </tr>\
    <tr>\
    <td>本卦</td>\
    <td>{tankyuunet(honka)}</td>\
    <td>{one_percent(honka)}</td>\
    <td>{ekikyonet(honka)}</a></td><td>{kou_text}</td>\
    <td>{ekikyodokugaku(honka,k1=kou4,k2=kou_text)}</td>\
    <td>今の状態</td>\
    <td>{hatikeHTML(honka)[1]}</td><td>{hatikeHTML(honka)[0]}</td>\
    </tr>\
    {sikaHTML}\
    <tr>\
    <td>互卦</td>\
    <td>{tankyuunet(goka)}</td>\
    <td>{one_percent(goka)}</td>\
    <td>{ekikyonet(goka)}</td><td></td>\
    <td>{ekikyodokugaku(goka)}</a></td>\
    <td>今の補足</td>\
    <td>{hatikeHTML(goka)[1]}</td><td>{hatikeHTML(goka)[0]}</td>\
    </tr>\
    <tr>\
    <td>賓卦</td>\
    <td>{tankyuunet(hinka)}</td>\
    <td>{one_percent(hinka)}</td>\
    <td>{ekikyonet(hinka)}</td><td></td>\
    <td>{ekikyodokugaku(hinka)}</td>\
    <td>相手の状態</td>\
    <td>{hatikeHTML(hinka)[1]}</td><td>{hatikeHTML(hinka)[0]}</td></td>\
    </tr>\
    <tr><td>裏卦</td>\
    <td>{tankyuunet(rika)}</td>\
    <td>{one_percent(rika)}</td>\
    <td>{ekikyonet(rika)}</td><td></td>\
    <td>{ekikyodokugaku(rika)}</a></td>\
    <td>裏の意味</td>\
    <td>{hatikeHTML(rika)[1]}</td><td>{hatikeHTML(rika)[0]}</td>\
    </tr>\
    </table>'))

# 内容
naiyou="ここに占いたい内容を書く"

printhtml()

リンク周りを書くにあたっては seleniumスクレイピングしてきたリンクアドレスをリスト化しております。

いろいろと書き直したらもうちょっとスマートになると思うのですが、とりあえず動くのでよしとして、よくわからない課金?サイトにいかなくて良くなったので良かった良かった。

ちなみに Google Colaboratory で動かしたら、re.match がうんたら言って動かなかったのでオンプレミスで*1

*1:よくわかっていないけれど、オンプレミスって言ってみたかった。