callmekohei's blog

callmekoheiのひとりごと

OANDA API を使ってトレード回数表を作ってみたった

f:id:callmekohei00:20170813140152p:plain

Summary

月度毎のトレード回数表を作成する

作成方法その1

ログイン > 口座管理 > 各種帳票ダウンロード > 取引履歴

で一ヶ月毎の帳票を出力して作成する

(よろしくないところ)
すごく手間がかかる

作成方法その2

REST APIを使用する

必要なもの

wget

jq

OANDAfs

wget, jqbrew install wget, brew install jqでもってこれます。

OANDAfsこちらから

トランザクションのデーターをもってくる

こんな感じ

#load "./oandafs.fsx"
open callmekohei
open callmekohei.Oandafs
let env   = Environment.Live
let id    = "xxxxx"
let token = "xxxxx"
let info  = API().Init( env, id, token )

Transaction(info).Get_all_transactions()
|> printfn "%A"

結果

Server: openresty/1.9.15.1
Date: Sun, 13 Aug 2017 05:06:54 GMT
Content-Type: application/json
Content-Length: 0
Connection: keep-alive
Location: https://fxtrade.oanda.com/transactionhistory/xxxxx.json.zip
Access-Control-Allow-Origin: *

ここでLocationに示されたアドレスからzipフィアルをげっつ

$ wget https://fxtrade.oanda.com/transactionhistory/xxxxx.json.zip

$ unzip xxxxx.json.zip
月度のトランザクションの総数を求める

こんなかんじ

$ cat abc.json \
> | jq 'map(select(.["time"] >= "2017-06-01T00:00:00Z")) | map(select(.["time"] <="2017-06-31T00:00:00Z"))' \
> | jq '.[] | .accountId' \
> | wc -w
     198
月度のトランザクションのタイプ別個数を求める

こんなかんじ

ここで先程のトランザクションの総数とタイプ別の個数の総数が一致しているか一応確認しておく

$ cat abc.json | jq 'map(select(.["time"] >= "2017-06-01T00:00:00Z")) | map(select(.["time"] <="2017-06-31T00:00:00Z"))' \
> | jq '.[] | .type' | sort | uniq -c | sort -r
 129 "MARKET_ORDER_CREATE"
  22 "MARGIN_CLOSEOUT"
  14 "DAILY_INTEREST"
   9 "ORDER_UPDATE"
   7 "TRANSFER_FUNDS"
   6 "ORDER_CANCEL"
   5 "BuyLimit"
   2 "ChangeOrder"
   1 "SellLimit"
   1 "ORDER_FILLED"
   1 "CloseOrder"
   1 "BuyStop"
月度の新規注文数を求める

こんなかんじ

$ cat abc.json | jq 'map(select(.["time"] >= "2017-06-01T00:00:00Z")) | map(select(.["time"] <="2017-06-31T00:00:00Z"))' \
> | jq '.[] | .tradeOpened.id' | sort | uniq | wc -w | awk '{print $1}'
73
月度の決済数を求める

こんなかんじ

CloseTradeB
MARGIN_CLOSEOUT
MARKET_ORDER_CREATE
ORDER_FILLED

上記の合計が総注文数となるので、そこから新規注文数をひけば決済数がでます。

ここでは総注文数が152、新規注文数が73なので決済数は

152 - 73 = 79

 年間のトレード回数表を作成する

こんなかんじ

foo.bash

jsonFile=$1
Year=$2

orderTotal() {
    file=$1; start=$2; end=$3
    cat $file \
    | jq 'map(select(.["time"] >= "'$start'")) | map(select(.["time"] <= "'$end'"))' \
    | jq '.[] | .type' | sort | grep -E "CloseTradeB|MARGIN_CLOSEOUT|MARKET_ORDER_CREATE|ORDER_FILLED" \
    | wc -w | awk '{print $1}'
}

openTotal() {
    file=$1; start=$2; end=$3
    cat $file \
    | jq 'map(select(.["time"] >= "'$start'")) | map(select(.["time"] <= "'$end'"))' \
    | jq '.[] | .tradeOpened.id' | sort | uniq | wc -w | awk '{print $1}'
}

echo 'M,Total,Open,Close'

for i in $(seq -w 1 12) ; do
    fst=$Year'-'$i'-01T00:00:00Z'
    lst=$Year'-'$i'-31T00:00:00Z'

    OrderTotal=`orderTotal $jsonFile $fst $lst`
    OpenTotal=`openTotal  $jsonFile $fst $lst`

    echo $i,$OrderTotal,$OpenTotal,$(( $OrderTotal - $OpenTotal ))
done

こんな感じで使う

csvlookはsudo pip3 install csvkitでゲッツ

$ echo ./abc.json 2017 | xargs bash foo.bash | csvlook
|  M | Total | Open | Close |
| -- | ----- | ---- | ----- |
|  1 |   142 |   68 |    74 |
|  2 |    77 |   39 |    38 |
|  3 |   105 |   51 |    54 |
|  4 |   116 |   52 |    64 |
|  5 |   150 |   68 |    82 |
|  6 |   152 |   73 |    79 |
|  7 |     0 |    0 |     0 |
|  8 |     2 |    3 |    -1 |
|  9 |     0 |    0 |     0 |
| 10 |     0 |    0 |     0 |
| 11 |     0 |    0 |     0 |
| 12 |     0 |    0 |     0 |
Remove all ads

Mac OSX で MT4 (MetaTrader4) をつかってみたった

f:id:callmekohei00:20170808211305p:plain

Summary

Mac OSXMetaTrader4を使う方法

準備

必要なもの

  1. PlayOnMac
  2. MetaTrader4

PlayOnMacをインストール

ここを参考にインストール

www.metatrader4.com

MacでMT4を使ってみよう | 株式会社クロスブリッジ XBRIDGE

re-dockの仕方

ウインドウとウインドウの間にフローティングしたウインドウをもってきて右側をダブルクリック

f:id:callmekohei00:20170810162525g:plain

custom indicators のインストール

f:id:callmekohei00:20170808204831p:plain

Step1

Data Folderをひらく

MT4 > File > Open Data Folder

Step2

indicators Folder をひらく

mql4 > indicators

Step3

もう一度 Data Folder をひらく

ファイルを保存した場所に行って Copy

Step4

Data Folder で Paste

Remove all ads

マックの環境復旧の個人的メモ

Summary

クリーンインストールしたmacを元の環境に戻すメモ

事のなり行き

先日、ターミナルでrm -rf /etcとかやったら

マックが立ち上がらなくなりました。

f:id:callmekohei00:20170802152638j:plain

先程アップルストア福岡に行ったら

可愛らしい若いエンジニアさんが

直してくれました!

f:id:callmekohei00:20170802152739j:plain

ので環境復旧します、します

Global setting

change keyboard layout

caps lockcontrolの位置をかえます

f:id:callmekohei00:20170802152029p:plain

f:id:callmekohei00:20170802152038p:plain

spotlight shortcut

command + r で検索窓を表示させます

f:id:callmekohei00:20170802151629p:plain

Japanese input method

日本語を入力できるようにします

入力ソースはHiraganaのみ

f:id:callmekohei00:20170802152304p:plain

ちなみに日本語と英語の切り替えはctrl + space

f:id:callmekohei00:20170805184720p:plain

install font

migmix-2mというfontを使えるようにします

まずmigmix-2mをダウンロードします

MigMixフォント : M+とIPAの合成フォント

つぎにfont Bookmigmix-2mを追加

spotlightを立ち上げて font Book と入力・リターン

ダウンロードした migmix-2m をdrag and drop

f:id:callmekohei00:20170802153738p:plain

other setting

その他こまごまと

siriをunableにする

バッテリー残を表示する

Dockをカーソルが来た時だけ表示する

キーボードのバックライトを消す

文字入力Live Conversionoffにする

Firefoxをインストールする

filename extensionsを表示させる

Excelをインストールする

Terminal setting

ターミナルの設定をやっていきます

terminalそのものの設定

preferenceから設定する

テーマを変える

github.com

フォントをmigmix-2m 14ptに変更

shellタブのwhen the shell exits:のところをClose the windowにする

bashの設定

.inputrcをつくる(bashの操作をvi風にする)

set editing-mode vi
set show-all-if-ambiguous on
set completion-ignore-case on

set keymap vi-command
    "\C-p": history-search-backward
    "\C-n": history-search-forward

set keymap vi-insert
    "\C-p": history-search-backward
    "\C-n": history-search-forward
    "\C-h": backward-char
    "\C-l": forward-char

.bash_profileをつくる

$ vim .bash_profile

if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

export LANG=ja_JP.UTF-8
export LESSCHARSET=utf-8

# PATH( left first )
p=""
p=$p'/usr/local/bin'
p=$p':/usr/local/sbin'
p=$p':/usr/sbin'
p=$p':/usr/bin'
p=$p':/bin'
p=$p':/sbin'

export PATH=$p

# NeoVim
export XDG_CONFIG_HOME=$HOME/.config
alias vim='nvim'

.bashrcをつくる

$ vim .bashrc

#!/bin/bash

# http://qiita.com/caad1229/items/6d71d84933c8a87af0c4
function parse_git_branch {
    git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ [\1]/'
}

function promps {
    local BLUE='\[\033[01;34m\]'
    local RED='\[\033[01;31m\]'
    local GREEN='\[\033[01;32m\]'
    local WHITE='\[\033[0;00m\]'
    local GRAY='\[\033[01;37m\]'
    PS1="${BLUE}\W${GREEN}\$(parse_git_branch)${BLUE}\$${WHITE} "
}

PROMPT_COMMAND='promps'
export CLICOLOR=1
export LSCOLORS=ExFxBxDxCxegedabagacad
export EDITOR=nvim

Vimの設定

VimNeovimに変更する

Home brew をインストール

下記のホームページのスクリプトをターミナルに貼り付けて実行

brew.sh

Neovimのインストール他

// neovim のインストール
$ brew install neovim

// Python3のインストール
$ brew install Python3

// Neovim Python3パッケージのインストール
$ pip3 install neovim

// Python2のインストール
$ brew install Python2

// Neovim Python2パッケージのインストール
$ pip2 install neovim

Neovimの設定

Neovimホームフォルダをつくる

$ mkdir -p ./.config/nvim

.config/nvimに下記を作成

dein.toml

#----------------------------------------------------------
# Shougo ware
#----------------------------------------------------------

[[plugins]]
repo = 'Shougo/dein.vim'

[[plugins]]
repo = 'Shougo/denite.nvim'

[[plugins]]
repo = 'Shougo/deoplete.nvim'
hook_add = '''
    let g:deoplete#enable_at_startup = 1
'''

[[plugins]]
repo = 'callmekohei/deoplete-fsharp'
build = 'bash install.bash'

[[plugins]]
repo = 'zchee/deoplete-jedi'

[[plugins]]
repo = 'Shougo/vimproc.vim'
build = 'make'


#----------------------------------------------------------
# Color scheme
#----------------------------------------------------------

# [[plugins]]
# repo = 'romainl/Apprentice'


#----------------------------------------------------------
# QuickRun
#----------------------------------------------------------

[[plugins]]
repo = 'thinca/vim-quickrun'
hook_add = '''
    set splitright
    let g:quickrun_config = {
    \
    \     '_' : {
    \           'runner'                          : 'vimproc'
    \         , 'runner/vimproc/updatetime'       : 60
    \         , 'hook/time/enable'                : 1
    \         , 'hook/time/format'                : "\n*** time : %g s ***"
    \         , 'hook/time/dest'                  : ''
    \         , "outputter/buffer/split"          : 'vertical'
    \         , 'outputter/buffer/close_on_empty' : 1
    \     }
    \
    \     , 'fsharp/fsharpi': {
    \           'exec'   :  [ '%c %s:p:r.fsx' ]
    \         , 'command':  'fsharpi'
    \         , 'args'   :  '%{input("args> ")}'
    \     }
    \
    \     , 'fsharp/fsharpc': {
    \           'exec'   :  [ '%c %s:p:r.fsx', 'mono %s:p:h/bin/%s:p:t:r.exe %a' ]
    \         , 'command':  'koheiEXE'
    \         , 'args'   :  '%{input("args> ")}'
    \     }
    \
    \     , 'fsharp/concurrent_process' : {
    \           'command'                         : 'fsharpi'
    \         , 'tempfile'                        : '%{tempname()}.fsx'
    \         , 'runner'                          : 'concurrent_process'
    \         , 'runner/concurrent_process/load'  : '#load "%S";;'
    \         , 'runner/concurrent_process/prompt': '> '
    \     }
    \
    \     , 'less': {
    \           'exec'   :  [ '%c -clean-css %s:p:r.less' ]
    \         , 'command':  'lessc'
    \     }
    \
    \     , 'python': {
    \           'command': 'python3'
    \     },
    \ }
'''
#----------------------------------------------------------
# Markdown browser
#----------------------------------------------------------

[[plugins]]
repo = 'plasticboy/vim-markdown'

[[plugins]]
repo = 'kannokanno/previm'
hook_add = '''
    let g:previm_open_cmd = 'open -a Firefox'
    let g:previm_disable_default_css = 1
    let g:previm_custom_css_path     = '/Users/kohei/.config/nvim/dein/repos/github.com/kannokanno/previm/preview/css/github.css'

    augroup PrevimSettings
      autocmd!
      autocmd BufNewFile,BufRead *.{md,mdwn,mkd,mkdn,mark*} set filetype=markdown
    augroup END

    let s:githubCss = "/Users/kohei/.config/nvim/dein/repos/github.com/kannokanno/previm/preview/css/github.css"
    let s:address   = "https://gist.githubusercontent.com/andyferra/2554919/raw/10ce87fe71b23216e3075d5648b8b9e56f7758e1/github.css"
    let s:folder    = "/Users/kohei/.config/nvim/dein/repos/github.com/kannokanno/previm/preview/css"

    if isdirectory(s:folder)
        if !filereadable(s:githubCss)
          execute '!wget' s:address '-P' s:folder
        endif
    endif
'''

#----------------------------------------------------------
# Util
#----------------------------------------------------------

[[plugins]]
repo = 'tomtom/tcomment_vim'
hook_add = '''
    if !exists('g:tcomment_types')
        let g:tcomment_types = {}
    endif
    let g:tcomment_types['fsharp'] = '// %s'
'''

[[plugins]]
repo = 'junegunn/vim-easy-align'
hook_add = '''
    xmap ga <Plug>(EasyAlign)
    nmap ga <Plug>(EasyAlign)
'''

[[plugins]]
repo = 'cespare/vim-toml'

init.vim

"----------------------------------------------------------
" Plugin manager ( Shougo/dein.vim )
"----------------------------------------------------------

let s:dein_dir = $HOME . '/.config/nvim/dein'
let s:toml     = $HOME . '/.config/nvim/dein.toml'

let s:dein_repo_dir = s:dein_dir . '/repos/github.com/Shougo/dein.vim'

if !isdirectory(s:dein_repo_dir)
    execute '!git clone https://github.com/Shougo/dein.vim' s:dein_repo_dir
endif

execute 'set runtimepath+=' . s:dein_repo_dir

if dein#load_state(s:dein_dir)
    call dein#begin(s:dein_dir)
    call dein#load_toml(s:toml, {'lazy': 0})
    call dein#end()
    call dein#save_state()
endif

if dein#check_install()
    call dein#install()
endif

filetype plugin indent on
syntax   enable

"----------------------------------------------------------
" Neovim's Python provider
"----------------------------------------------------------
let g:python_host_prog  = '/usr/local/bin/python2.7'
let g:python3_host_prog = '/usr/local/bin/python3.6'

"----------------------------------------------------------
" General
"----------------------------------------------------------
" Tab
set shiftwidth=4            "vimが自動でインデントを行った際、設定する空白数
set tabstop=4               "<TAB>を含むファイルを開いた際、<TAB>を何文字の空白に変換するかを設定
set softtabstop=4           "キーボードで<TAB>を入力した際、<TAB>を何文字の空白に変換するかを設定
set expandtab               "タブ文字を空白に設定する。shofttabstopとセットで使用すると便利

" Clipbord ( see : help clipboard )
set clipboard+=unnamedplus 

" Mouse ( see :help mouse-using )
set mouse=nvic

set nowrap
set number
set noswapfile
set cmdheight=2

"----------------------------------------------------------
" Seek
"----------------------------------------------------------
set wrapscan
set ignorecase
set smartcase
nnoremap <silent> <C-l> :nohlsearch<CR>

"----------------------------------------------------------
" Appearance
"----------------------------------------------------------
" colorscheme birds-of-paradise
" colorscheme Apprentice


" English menu display
source $VIMRUNTIME/delmenu.vim
set    langmenu=none
source $VIMRUNTIME/menu.vim

if has("multi_lang")
    language en_gb
endif

"----------------------------------------------------------
" Char code
"----------------------------------------------------------
set encoding=utf-8
set fileencodings=utf-8,iso-2022-jp,euc-jp,sjis

check

$ vim abc.fsx

"hello world"
|> stdout.Write
hello world

その他のコマンド

wget

hub gibo

Remove all ads

F#でお気楽にテスト!(Persimmon.Script編)

Summary

とにかく手間をかけずにテストしたい人

Persimmon.Scriptで決まり!

Persimmon.Scriptとは?

F#スクリプトお気楽にテストできるライブラリ〜

つまりはメンドくさがりな人向けのライブラリ〜

特徴

  1. とにかく手間がかからない

  2. お手軽なのでテストファースト的に使える
    (テスト書いて実行がサクサクできる)

  3. Travisなどのテストスクリプトも簡単にかける
    exe,dll依存をconfigファイルに書く必要がない)

使い方

まずはPersimmon.Scriptnugetしませう。

nuget persimmon.script

こんな感じのコードを書いてみる

/// Persimmonライブラリ一式をrequire and open
#r "./packages/Persimmon/lib/net45/Persimmon.dll"
#r "./packages/Persimmon.Runner/lib/net40/Persimmon.Runner.dll"
#r "./packages/Persimmon.Script/lib/net45/Persimmon.Script.dll"
open Persimmon
open UseTestNameByReflection

/// テストレポート出力用に必要
open System.Reflection

/// こんな感じでテストをかく
let myTest = test {
    do! assertEquals 1 2
}

/// テスト結果を出力
Script.testReport( fun _ -> Assembly.GetExecutingAssembly() )
|> stdout.WriteLine

結果

begin FSI_0001
 Assertion Violated: myTest
 1. Expect: 1
    Actual: 2
end FSI_0001
============================== summary ===============================
run: 1, error: 0, violated: 1, skipped: 0, duration: 00:00:00.0840830

本当にお手軽ですね!

さらに

従来だとexe, dllの依存関係をPersimmon.Console.exe.configファイルに

書かないといけませんでしたが、

Persimmon.Scriptだとその必要がないです。

よくわからないかもしれませんが

つまりはお手軽〜なのです。

こんな感じ

外部Dll

add10.fsx

namespace callmekohei

module Util =
    let add10 n =
        n + 10

これを $ fsahrpc -a add10.fsxとしてadd10.dllを作る

code
/// 外部dll(依存してるdll)をrequireするだけ!
#r "./add10.dll"
open callmekohei.Util

/// Persimmonライブラリ一式をrequire and open
#r "./packages/Persimmon/lib/net45/Persimmon.dll"
#r "./packages/Persimmon.Runner/lib/net40/Persimmon.Runner.dll"
#r "./packages/Persimmon.Script/lib/net45/Persimmon.Script.dll"
open Persimmon
open UseTestNameByReflection

/// テストレポート出力用に必要
open System.Reflection

/// テストを書く
let myTest = test {
    do! assertEquals 1 ( add10 1 )
}

/// テスト結果を出力
Script.testReport( fun _ -> Assembly.GetExecutingAssembly() )
|> stdout.WriteLine

結果

begin FSI_0005.MyTest_deoplete-fsharp_temporary_file
Assertion Violated: myTest
1. Expect: 1
Actual: 11
end FSI_0005.MyTest_deoplete-fsharp_temporary_file
============================== summary ===============================
run: 1, error: 0, violated: 1, skipped: 0, duration: 00:00:00.0687324

本当にお手軽ですね!

感想

本当に便利なライブラリをありがとうございます!!!

参考

Persimmon.Scriptはここからナゲット!(ダウンロード)

NuGet Gallery | Packages matching persimmon.script

開発に参加したい・要望がある〜という人はこちら

github.com

Remove all ads

F#を気軽にテスト〜・それVimで

Summary

F#のコードをVimで手軽にテストしてみた

こんな感じ

必要なもの

  • Neovim
  • deoplete-fsharp

テストの仕方

  • Persimmonをゲッツ(Nuget, Paketおこのみで)
  • テストコードを書く
  • :Persimmonコマンドを実行

いいところ

気軽にテストできるところ(Persimmonコマンドを入力するだけ)

残念なところ

結果が出るまでに3秒ほどかかること

ちょっとした解説

Persimmonコマンドは以下のように動作します

同じフォルダに`Persimmon.Console.exe`があるか?
↓
同じフォルダに`tools`フォルダがあるか?(あればそのなかに`Persimmon.Console.exe`があるか?)
↓
同じフォルダに`Packages`フォルダがあるか?(あればそのなかに`Persimmon.Console.exe`があるか?)
↓
上記で見つからなければ`deoplete-fsharp`の`Persimmon.Console.exe`を使う






tutorial 01

Persimmon を使った簡単なテスト

paketコマンドはこちらを参照

// 実験フォルダをつくる
$ mkdir jikken

// 実験フォルダに移動
$ cd jikken

// paketを初期化
$ paket init

// ダウンロードするファイルをかく
$ vim paket.dependencies 

***********************
*
*   source https://www.nuget.org/api/v2
*   nuget Persimmon.Console -OutputDirectory tools -ExcludeVersion
*
***********************

// ダウンロード
$ paket install

// テストコードをかく
$ vim test.fsx

code

#r "./packages/Persimmon.Console/tools/Persimmon.dll"
open Persimmon
open UseTestNameByReflection

let add   x y = x + y

let ``first test example`` = test {
    do! assertEquals 6 (add 1 5)
}

Persimmonコマンドを実行

: Persimmon

結果

.
============================== summary ===============================
run: 1, error: 0, violated: 0, skipped: 0, duration: 00:00:00.0934450


*** time : 3.035613 s ***


tutorial 02

tutorial 01 のつづき( jikken フォルダーにいるものとします)

依存のある`dll, exe`をサブフォルダにまとめる方法


dll, exeをまとめるlibフォルダをつくってPersimmonのサブフォルダにする

// libフォルダをつくる
$ mkdir lib

// コードをかく
$ vim ./lib/hello.fsx

code

namespace callmekohei

module Hello =

    let say (word:string) =
        word + " hello!"
// dllファイルを作成
$ fsharpc -a ./lib/hello.fsx

// libフォルダを Persimmon.Console.exe の下におく
$ mv  /lib packages/Persimmon.Console/tools/

ファイルの状況
jikken$ tree packages/
packages/
├── Paket
│   ├── Paket.nupkg
│   └── tools
│       └── paket.exe
└── Persimmon.Console
    ├── Persimmon.Console.2.0.1.nupkg
    ├── Persimmon.Console.nuspec
    ├── [Content_Types].xml
    ├── _rels
    ├── license.html
    ├── package
    │   └── services
    │       └── metadata
    │           └── core-properties
    │               └── coreProp.psmdcp
    └── tools
        ├── FSharp.Core.dll
        ├── Persimmon.Console.exe
        ├── Persimmon.Console.exe.config
        ├── Persimmon.Runner.dll
        ├── Persimmon.Runner.dll.config
        ├── Persimmon.dll
        ├── Persimmon.dll.config
        ├── System.ValueTuple.dll
        └── lib    <-------------------- sub foler!
            ├── hello.dll
            └── hello.fsx

10 directories, 17 files

設定ファイル(Persimmon.Console.exe.config)を書き直す

$ vim packages/Persimmon.Console/tools/Persimmon.Console.exe.config 

下記のようにかく(<probing privatePath="lib"/>を追加するだけ)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      
      <!-- Look for addins in the addins directory for now -->
      <probing privatePath="lib"/> 
      
      <dependentAssembly>
        <assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.4.1.0" newVersion="4.4.1.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

テストファイルを作成する

// テストファイル test2.fsx を作成する
$ vim test2.fsx

code

#r "./packages/Persimmon.Console/tools/Persimmon.dll"
open Persimmon
open UseTestNameByReflection

#r "./packages/Persimmon.Console/tools/lib/hello.dll"
open callmekohei


let ``first test example`` = test {
    do! assertEquals "abc" ( Hello.say "hello" )
}

test実施(Persimmonコマンド実行)

: Persimmon

結果

x
begin Test2_deoplete-fsharp_temporary_file
Assertion Violated: first test example
1. Expect: "abc"
Actual: "hello hello!"
end Test2_deoplete-fsharp_temporary_file
============================== summary ===============================
run: 1, error: 0, violated: 1, skipped: 0, duration: 00:00:00.1194835


*** time : 2.941333 s ***

おまけ

超気軽なテスト

code

#r "./packages/Persimmon.Console/tools/Persimmon.dll"
open Persimmon

let add   x y = x + y

assertEquals 1 ( add 1 1)
|> printfn "%A"

:QUICKRUNfsを実行

NotPassed (None,Violated "Expect: 1
Actual: 2")


*** time : 0.072349 s ***

これならはやい!

Remove all ads

dllファイルをサブフォルダーにおく

Summary

依存するdllファイルはexeファイルと同じフォルダに置くのが一般的

依存するdllをサブフォルダーに置く方法

方法

configファイルを作成する

ファイル構成

gimBeam.exeがメイン

highball$ tree
.
├── dll
│   ├── FSharp.Compiler.Service.dll
│   ├── FSharp.Core.dll
│   ├── Newtonsoft.Json.dll
│   ├── deopletefs.exe
│   └── log.txt
├── gimBeam.exe
├── gimBeam.exe.config
└── gimBeam.fsx

1 directory, 8 files

config ファイル

gimBeam.exe.configをつくって下記を入力

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

   <!-- Look for addins in the addins directory for now -->
      <probing privatePath="dll"/>

    </assemblyBinding>
  </runtime>
</configuration>

留意事項

依存するdllファイルは同じフォルダかサブフォルダしかおけない

privatePath は親フォルダを指定できない仕様
Remove all ads

F#をさっさと学ぶ〜( F#入門・学習)

Summary

F#を1年半お勉強して個人的に思ったことなど、など

1〜2週間ぐらいでさっさとF#を書きたい人向け

心構え

  • F#はそんなに難しくない

  • 難易度はPythonとかと同じでVBAよりも簡単

  • .netを活用することがキモになる

  • とかく日本語の情報がすくない(英語力がないと情報をとれない)

  • C#とか.netとかを当然知ってるでしょ?という前提で説明してくる人が多い(ビギナーにやさしくない)

  • 正直ビギナーには情報がなくて厳しいかも

レベル別学習方法

ビギナー

ビギナーのための本・チュートリアルはないような気がする・・・

初級

fsharpintro.net

中級

実践 F# 関数型プログラミング入門

実践 F# 関数型プログラミング入門

プログラミングF#

プログラミングF#

上級(英語を読める力が必要)

www.gitbook.com

F# Programming - Wikibooks, open books for an open world

リファレンス(ど忘れした時とかに便利)

github.com

今後に期待(今は作成中っぽい・・・)

docs.microsoft.com

お勉強中にわからなかったら

  • まず本とかネットとかで情報をさがす

  • チャット(gitter)で聞いてみる(Githubのアカウントが必要)

  • チャット(slack)で聞いてみる(登録が必要)

  • 質問サイト(stackoverflow)で聞いてみる(登録が必要)

  • Twitterで聞いてみる(#fsharpとつけるといいかも?)

Remove all ads

なんとなく FizzBuzz かいてみた

なんかハイボール片手にツイッターをぼけ〜っとみてたら

FizzBuzzしたくなったのでかいてみた!

こんな感じ

コード

fizzbuzz.fsx

#load "./interaction.fsx"
open callmekohei.Interaction

let (|Div|_|) by n = if n % by = 0 then Some Div else None

let fizzbuzz = function
    | Div 15 -> "FizzBuzz"
    | Div  5 -> "Buzz"
    | Div  3 -> "Fizz"
    | n      -> string n

let rec main s =
    match s with
    | "init" -> stdout.WriteLine("--- start ---")
                main ( stdin.ReadLine() )
    | "quit" -> printer.Quit()
    | _ when fst (System.Int32.TryParse(s)) = false -> 
        stdout.WriteLine("数字を入力してください!")
        main ( stdin.ReadLine() )
    | _      -> printer.WriteLine(fizzbuzz(int s))
                main ( stdin.ReadLine() )

main "init"

interaction.fsx

namespace callmekohei
module Interaction =

    type PrinterAgent() =
        let inbox = MailboxProcessor.Start( fun inbox ->
            let rec loop () = async {
                let! ( msg : Choice< string , AsyncReplyChannel<unit> > ) = inbox.Receive()
                match msg with
                | Choice1Of2 (s:string) ->
                    stdout.WriteLine(s)
                    return! loop ()
                | Choice2Of2 (ch : AsyncReplyChannel<unit>) -> ch.Reply ()
            }
            loop ()
        )

        member x.WriteLine(s) = inbox.Post ( Choice1Of2 s )
        member x.Quit()       = inbox.PostAndReply(fun ch -> Choice2Of2 ch)

    let printer = PrinterAgent()

みどころ〜

アクティブパターンなところ

数字かどうか判定〜

mailboxporcessorをつかってるところ〜(マルチスレッドでも安全!)
Remove all ads

F#で簡単プロセス間通信

Summary

親子プロセスでの通信

こんな感じ

$ mono abc.exe 
HELLO from child process
hello --- from child process --- 
apple
apple --- from child process --- 
banana
banana --- from child process --- 
cherry
cherry --- from child process --- 
quit

$ 

子プロセス

文字を入力するとabc --- from child process ---と返す

let rec main s =
    match s with
    | "quit" -> ()
    | "init" -> stdout.WriteLine("HELLO from child process")
                main ( stdin.ReadLine() )
    | _      -> stdout.WriteLine( s + " --- from child process --- " )
                main ( stdin.ReadLine() )

[<EntryPointAttribute>]
let entry arg =
    main "init"
    0

親プロセス

親プロセスで文字を入力

→ 子プロセスに文字を送る

→ 子プロセスの標準出力が出力されたら取得する(イベントで見張ってる)

open System.Diagnostics

type Interaction (fp:string, args:string, wd:string) =
    
    // 子プロセスの起動パラメータを作成する
    let procStartInfo =
        ProcessStartInfo(
            FileName               = fp   ,
            Arguments              = args ,
            WorkingDirectory       = wd   ,
            RedirectStandardInput  = true , // 子プロセスの標準入力をリダイレクトする
            RedirectStandardOutput = true , // 子プロセスの標準出力をリダイレクトする
            RedirectStandardError  = true , // 子プロセスの標準エラーをリダイレクトする
            UseShellExecute        = false  // シェルを使用せず子プロセスを起動する(リダイレクトするために必要)
    )
    
    // 子プロセスをインスタンス化
    let ps = new Process(StartInfo = procStartInfo)

    // Set our event handler to asynchronously read the ps output.
    // リダイレクトした標準出力の内容を受信するイベントハンドラを設定する
    do ps.OutputDataReceived
       |> Event.add ( fun (args :DataReceivedEventArgs) ->
           stdout.WriteLine(args.Data) |> ignore )
    
    // 子プロセスを起動する
    do ps.Start() |> ignore
    // 子プロセスがアイドル状態になるまで無期限に待機
    do ps.WaitForInputIdle() |>ignore
    // Start the asynchronous read of the ps output stream.
    // 標準出力の非同期読み込みを開始する
    do ps.BeginOutputReadLine()

    // リダイレクトした子プロセスの標準入力にテキストを書き込む
    member this.Send(message:string) = ps.StandardInput.WriteLine(message)
    
    // 子プロセスを終了する
    member this.Quit() = ps.Kill()



let mono    = "/usr/local/Cellar/mono/4.8.1.0/bin/mono"
let args    = "/Users/kohei/Documents/childProcess.exe"
let workdir = "/Users/kohei/Documents/"
let replyer = Interaction(mono,args,workdir)

let rec main s =
    match s with
    | "quit" -> replyer.Quit()
    | _      -> replyer.Send(s)
                main ( stdin.ReadLine() )

[<EntryPointAttribute>]
let entry arg =
    main "hello"
    0
Remove all ads

TravisからGithubにpushしてみた〜

f:id:callmekohei00:20170709142719p:plain

Summary

TravisからGithubpushしてみた

かなりハマったのでメモメモ。

はまり

下記が表示されて処理が前に進まない・・・

$ git clone git@github.com:callmekohei/deoplete-fsharp-bin.git
Cloning into 'deoplete-fsharp-bin'...
Enter passphrase for key '/home/travis/.ssh/id_rsa': 

原因

(その1)

passphraseを設定した

$ ssh-keygen -f deploy_key

keyを作る際にりーたん・りたーんするところを何かしらキーを押したっぽい?

(その2)

sshの設定?

一応下記のようにして ~/.ssh/configappendした

Host github.com
    User git
    StrictHostKeyChecking no
    IdentityFile ~/.ssh/id_rsa
    IdentitiesOnly yes
    ForwardAgent yes

(その3)

gitリポジトリを作り直すとだめになる?

多分最初のpushはだめかも。。。

対処

結局、再度キーペア作り直すと

ちゃんとうごきました

手順

gist.github.com

参考

www.tam-tam.co.jp

Remove all ads

easy debug with deoplete source

Summary

easy debug with deoplete source

Method

(step 1) use debug function

from .base import Base
from deoplete.util import debug # <--- point!!!

class Source(Base):
    def __init__(self, vim):
        super().__init__(vim)
        self.name = 'callmekohei'
        self.mark = '[callmekohei]'
        self.filetypes = ['text']

    def gather_candidates(self, context):
        debug(self.vim,"callmekohei") # <--- point!!!
        return ["apple","banana","cherry"]


(step 2)

: set cmdhight=3
Remove all ads

FParsecのメモ

たんなる雑記メモですっ

#r @"./packages/FParsec/lib/portable-net45+netcore45+wpa81+wp8/FParsecCS.dll"
#r @"./packages/FParsec/lib/portable-net45+netcore45+wpa81+wp8/FParsec.dll"
open FParsec

"hello world" |> run (many letter) |> printfn "%A"
/// Success: ['h'; 'e'; 'l'; 'l'; 'o']

"hello world" |> run (manyChars letter) |> printfn "%A"
/// Success: "hello"

"hello world" |> run ( sepBy (manyChars letter) (pchar ' ')) |> printfn "%A"
/// Success: ["hello"; "world"]

"hello, world"
|> run (sepBy ( manyChars letter ) ( pstring "," .>> spaces ))
|> fun x -> match x with Success (lst,_,_) -> lst | _ -> []
|> printfn "%A"
/// ["hello"; "world"]

"hello00 world99"
|> run (sepBy (manyChars (letter <|> digit)) (pchar ' ')) |> printfn "%A"
/// Success: ["hello00"; "world99"]

"hello00 world99"
|> run (sepBy ( (manyChars letter) .>> (manyChars digit) ) (pchar ' ')) |> printfn "%A"
/// Success: ["hello"; "world"]
Remove all ads

FParsecをさわってみた!

Summary

文字をパースするFParsecというライブラリを触ってみました

こんなかんじ

#r @"./packages/FParsec/lib/portable-net45+netcore45+wpa81+wp8/FParsecCS.dll"
#r @"./packages/FParsec/lib/portable-net45+netcore45+wpa81+wp8/FParsec.dll"
open FParsec

let test p str =
    match run p str with
    | Success(result, _, _)   -> printfn "Success: %A" result
    | Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg

test pfloat "1.25" /// Success: 1.25

ポイント

dllに優先順位(依存関係)があるので上記のようにFParseCS.dllを上に書いてからFParse.dllをかく

参考

Tutorial

還暦プログラマの挑戦(Haskell に挑む→F#による言語造り)

komorebikoboshi.hatenablog.com

hafuu.hatenablog.com

Remove all ads

F#のMailboxProcessorのメモ

シンプルなエージェント

/// エージェントを作成する( Queueに入れるタイプを指定する、async式を返す式を指定する)
let simpleAgent = new MailboxProcessor<string>(fun _ -> async { () })

/// Queueに文字を入れる
simpleAgent.Post("hello")

/// Queueに入ってる文字列の数を調べる
simpleAgent.CurrentQueueLength |> stdout.WriteLine // 1

simpleAgent.Post("world")
simpleAgent.CurrentQueueLength |> stdout.WriteLine // 2

/// Queueに入ってる文字列をすべて調べる
simpleAgent.TryScan( fun x ->
    stdout.WriteLine(x)
    if x = null then Some(async{()}) else None
,timeout = 1) |> Async.RunSynchronously |> ignore
// hello
// world

/// Queueからエージェント側に文字列を取得する
simpleAgent.Receive() |> Async.RunSynchronously |> stdout.WriteLine // hello

/// Queueに入ってる文字列の数を調べる
simpleAgent.CurrentQueueLength |> stdout.WriteLine // 1

simpleAgent.Receive() |> Async.RunSynchronously |> stdout.WriteLine // world
simpleAgent.CurrentQueueLength |> stdout.WriteLine // 0

エージェントから値を取得する

let replyAgent = MailboxProcessor.Start( fun inbox ->
    async {
        let! (ch:AsyncReplyChannel<_>) = inbox.Receive()
        ch.Reply "hello"
    }
)
replyAgent.PostAndReply id |> stdout.WriteLine
/// hello

FizzBuzzしてみた

let (|Div|_|) by n = if n % by = 0 then Some Div else None

let fizzbuzz = function
    | Div 15 -> "FizzBuzz"
    | Div  5 -> "Buzz"
    | Div  3 -> "Fizz"
    | n      -> string n

type Command = Add of int | Fetch of AsyncReplyChannel<string list>

let fizzbuzzAgent = MailboxProcessor.Start( fun inbox ->
    
    let rec loop lst = async{
        let! msg = inbox.Receive()
        match msg with
        | Add value ->
            return! loop ( fizzbuzz value :: lst )
        | Fetch ch ->
            ch.Reply(lst)
            return! loop lst
    }
    loop []
)

[1..100] |> List.iter( fun n -> fizzbuzzAgent.Post(Add n) )

fizzbuzzAgent.PostAndReply(Fetch)
|> List.rev
|> List.iter stdout.WriteLine

結果

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
以下略

ちょっとした電卓

type Command = AllClear | Add of int | Enter of AsyncReplyChannel<int * Command list>
    
let CalcAgent = MailboxProcessor.Start( fun inbox -> 

    let rec loop n lst = async {
        match inbox.Receive() |> Async.RunSynchronously with
        | AllClear   -> return! loop 0 []
        | Enter repl -> repl.Reply( n , lst |> List.rev ) ; return! loop n lst
        | Add value  -> return! loop (value + n) ( Add value   :: lst )
    }
    loop 0 []
)

CalcAgent.Post(Add 8)
CalcAgent.Post(Add 5)
CalcAgent.Post(Add -3)
CalcAgent.PostAndReply(Enter) |> printfn "%A"
/// (10, [Add 8; Add 5; Add -3])

CalcAgent.Post(AllClear)

CalcAgent.Post(Add 1)
CalcAgent.Post(Add 5)
CalcAgent.Post(Add -2)
CalcAgent.PostAndReply(Enter) |> printfn "%A"
/// (4, [Add 1; Add 5; Add -2])
Remove all ads

F#でprintデバッグしてみる〜

sample code

コードはこんな感じで

open System.Diagnostics

/// Debugモードのときだけコンパイルする
#if DEBUG
/// リスナーをインスタンス化する
let listener  = new DefaultTraceListener()
/// logファイルを指定する
let parentDic = System.Reflection.Assembly.GetEntryAssembly().Location |> fun x -> string ( System.IO.Directory.GetParent(x) )
listener.LogFileName <- System.IO.Path.Combine( parentDic, "log.txt" )
/// リスナーに追加する
Debug.Listeners.Add(listener)
#endif

let rec main s (acc:int)=
    match s with
    | "quit" -> () /// quitという文字列で終了する
    | _      -> 
                /// stdoutから出力する
                stdout.WriteLine(s)
                /// log.txtに出力する
                Debug.WriteLine(acc)
                main (stdin.ReadLine()) (acc + 1)

[<EntryPointAttribute>]
let entry arg =
    main arg.[0] 0
    0

デバッグのしかた

まずdebugモードでコンパイル

$ fsharpc -d:DEBUG abc.fsx

で、ログファイルをリッスン

Fを押してForward foreverとする

$ less log.txt

実行してみる

$ mono abc.exe callmekohei
/// 標準出力へ
callmekohei
/// log.txtへ
0
Remove all ads