clickclient_scrap 0.1.9 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +5 -0
- data/lib/clickclient_scrap.rb +726 -688
- data/lib/jiji_plugin.rb +17 -8
- data/sample/constants.rb +5 -0
- data/sample/sample_get_margin.rb +24 -0
- data/sample/sample_list_open_interests.rb +25 -0
- data/sample/sample_list_orders.rb +28 -0
- data/sample/sample_list_rates.rb +16 -0
- data/sample/sample_market_order.rb +21 -0
- data/sample/sample_oco_order.rb +36 -0
- data/sample/sample_order.rb +64 -0
- data/sample/sample_settle.rb +18 -0
- data/specs/cancel_order_spec.rb +43 -0
- data/specs/common.rb +30 -0
- data/specs/jiji_plugin_spec!.rb +127 -0
- data/specs/limit_order_spec.rb +98 -0
- data/specs/list_orders_spec.rb +28 -0
- data/specs/market_order_spec!.rb +131 -0
- data/specs/oco_order_spec.rb +60 -0
- data/specs/order_error_spec.rb +139 -0
- metadata +27 -6
- data/test/test_FxSession.rb +0 -38
- data/test/test_jiji_plugin.rb +0 -77
data/ChangeLog
CHANGED
data/lib/clickclient_scrap.rb
CHANGED
@@ -1,690 +1,728 @@
|
|
1
|
-
begin
|
2
|
-
require 'rubygems'
|
3
|
-
rescue LoadError
|
4
|
-
end
|
5
|
-
require 'mechanize'
|
6
|
-
require 'date'
|
7
|
-
require 'kconv'
|
8
|
-
require 'set'
|
9
|
-
|
10
|
-
#
|
11
|
-
#=== クリック証券アクセスクライアント
|
12
|
-
#
|
13
|
-
#*Version*:: -
|
14
|
-
#*License*:: Ruby ライセンスに準拠
|
15
|
-
#
|
16
|
-
#クリック証券を利用するためのクライアントライブラリです。携帯向けサイトのスクレイピングにより以下の機能を提供します。
|
17
|
-
#- 外為証拠金取引(FX)取引
|
18
|
-
#
|
19
|
-
#====基本的な使い方
|
20
|
-
#
|
21
|
-
# require 'clickclient_scrap'
|
22
|
-
#
|
23
|
-
# c = ClickClient::Client.new
|
24
|
-
# # c = ClickClientScrap::Client.new https://<プロキシホスト>:<プロキシポート> # プロキシを利用する場合
|
25
|
-
# c.fx_session( "<ユーザー名>", "<パスワード>" ) { | fx_session |
|
26
|
-
# # 通貨ペア一覧取得
|
27
|
-
# list = fx_session.list_rates
|
28
|
-
# puts list
|
29
|
-
# }
|
30
|
-
#
|
31
|
-
#====免責
|
32
|
-
#- 本ライブラリの利用は自己責任でお願いします。
|
33
|
-
#- ライブラリの不備・不具合等によるあらゆる損害について、作成者は責任を負いません。
|
34
|
-
#
|
35
|
-
module ClickClientScrap
|
36
|
-
|
37
|
-
# クライアント
|
38
|
-
class Client
|
39
|
-
# ホスト名
|
40
|
-
DEFAULT_HOST_NAME = "https://sec-sso.click-sec.com/mf/"
|
41
|
-
DEFAULT_DEMO_HOST_NAME = "https://www.click-sec.com/m/demo/"
|
42
|
-
|
43
|
-
#
|
44
|
-
#===コンストラクタ
|
45
|
-
#
|
46
|
-
#*proxy*:: プロキシホストを利用する場合、そのホスト名とパスを指定します。
|
47
|
-
# 例) https://proxyhost.com:80
|
48
|
-
#
|
49
|
-
def initialize( proxy=ENV["http_proxy"], demo=false )
|
50
|
-
@client = WWW::Mechanize.new {|c|
|
51
|
-
# プロキシ
|
52
|
-
if proxy
|
53
|
-
uri = URI.parse( proxy )
|
54
|
-
c.set_proxy( uri.host, uri.port )
|
55
|
-
end
|
56
|
-
}
|
57
|
-
@client.keep_alive = false
|
58
|
-
@client.max_history=0
|
59
|
-
@client.user_agent_alias = 'Windows IE 7'
|
60
|
-
@demo = demo
|
61
|
-
@host_name = @demo ? DEFAULT_DEMO_HOST_NAME : DEFAULT_HOST_NAME
|
62
|
-
end
|
63
|
-
|
64
|
-
#ログインし、セッションを開始します。
|
65
|
-
#-ブロックを指定した場合、引数としてセッションを指定してブロックを実行します。ブロック実行後、ログアウトします。
|
66
|
-
#-そうでない場合、セッションを返却します。この場合、ClickClientScrap::FX::FxSession#logoutを実行しログアウトしてください。
|
67
|
-
#
|
68
|
-
#userid:: ユーザーID
|
69
|
-
#password:: パスワード
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
require 'mechanize'
|
6
|
+
require 'date'
|
7
|
+
require 'kconv'
|
8
|
+
require 'set'
|
9
|
+
|
10
|
+
#
|
11
|
+
#=== クリック証券アクセスクライアント
|
12
|
+
#
|
13
|
+
#*Version*:: -
|
14
|
+
#*License*:: Ruby ライセンスに準拠
|
15
|
+
#
|
16
|
+
#クリック証券を利用するためのクライアントライブラリです。携帯向けサイトのスクレイピングにより以下の機能を提供します。
|
17
|
+
#- 外為証拠金取引(FX)取引
|
18
|
+
#
|
19
|
+
#====基本的な使い方
|
20
|
+
#
|
21
|
+
# require 'clickclient_scrap'
|
22
|
+
#
|
23
|
+
# c = ClickClient::Client.new
|
24
|
+
# # c = ClickClientScrap::Client.new https://<プロキシホスト>:<プロキシポート> # プロキシを利用する場合
|
25
|
+
# c.fx_session( "<ユーザー名>", "<パスワード>" ) { | fx_session |
|
26
|
+
# # 通貨ペア一覧取得
|
27
|
+
# list = fx_session.list_rates
|
28
|
+
# puts list
|
29
|
+
# }
|
30
|
+
#
|
31
|
+
#====免責
|
32
|
+
#- 本ライブラリの利用は自己責任でお願いします。
|
33
|
+
#- ライブラリの不備・不具合等によるあらゆる損害について、作成者は責任を負いません。
|
34
|
+
#
|
35
|
+
module ClickClientScrap
|
36
|
+
|
37
|
+
# クライアント
|
38
|
+
class Client
|
39
|
+
# ホスト名
|
40
|
+
DEFAULT_HOST_NAME = "https://sec-sso.click-sec.com/mf/"
|
41
|
+
DEFAULT_DEMO_HOST_NAME = "https://www.click-sec.com/m/demo/"
|
42
|
+
|
43
|
+
#
|
44
|
+
#===コンストラクタ
|
45
|
+
#
|
46
|
+
#*proxy*:: プロキシホストを利用する場合、そのホスト名とパスを指定します。
|
47
|
+
# 例) https://proxyhost.com:80
|
48
|
+
#
|
49
|
+
def initialize( proxy=ENV["http_proxy"], demo=false )
|
50
|
+
@client = WWW::Mechanize.new {|c|
|
51
|
+
# プロキシ
|
52
|
+
if proxy
|
53
|
+
uri = URI.parse( proxy )
|
54
|
+
c.set_proxy( uri.host, uri.port )
|
55
|
+
end
|
56
|
+
}
|
57
|
+
@client.keep_alive = false
|
58
|
+
@client.max_history=0
|
59
|
+
@client.user_agent_alias = 'Windows IE 7'
|
60
|
+
@demo = demo
|
61
|
+
@host_name = @demo ? DEFAULT_DEMO_HOST_NAME : DEFAULT_HOST_NAME
|
62
|
+
end
|
63
|
+
|
64
|
+
#ログインし、セッションを開始します。
|
65
|
+
#-ブロックを指定した場合、引数としてセッションを指定してブロックを実行します。ブロック実行後、ログアウトします。
|
66
|
+
#-そうでない場合、セッションを返却します。この場合、ClickClientScrap::FX::FxSession#logoutを実行しログアウトしてください。
|
67
|
+
#
|
68
|
+
#userid:: ユーザーID
|
69
|
+
#password:: パスワード
|
70
70
|
#options:: オプション
|
71
|
-
#戻り値:: ClickClientScrap::FX::FxSession
|
72
|
-
def fx_session( userid, password, options={}, &block )
|
73
|
-
page = @client.get(@host_name)
|
74
|
-
ClickClientScrap::Client.error(page) if page.forms.length <= 0
|
75
|
-
form = page.forms.first
|
76
|
-
form.j_username = userid
|
77
|
-
form.j_password = password
|
78
|
-
result = @client.submit(form, form.buttons.first)
|
79
|
-
# デモサイトではjsによるリダイレクトは不要。
|
80
|
-
if !@demo
|
81
|
-
if result.body.toutf8 =~ /<META HTTP-EQUIV="REFRESH" CONTENT="0;URL=([^"]*)">/
|
82
|
-
result = @client.get($1)
|
83
|
-
ClickClientScrap::Client.error( result ) if result.links.size <= 0
|
84
|
-
else
|
85
|
-
ClickClientScrap::Client.error( result )
|
86
|
-
end
|
87
|
-
end
|
88
|
-
session = FX::FxSession.new( @client, result.links, options )
|
89
|
-
if block_given?
|
90
|
-
begin
|
91
|
-
yield session
|
92
|
-
ensure
|
93
|
-
session.logout
|
94
|
-
end
|
95
|
-
else
|
96
|
-
return session
|
97
|
-
end
|
98
|
-
end
|
99
|
-
def self.error( page )
|
100
|
-
msgs = page.body.scan( /<font color="red">([^<]*)</ ).flatten
|
101
|
-
error = !msgs.empty? ? msgs.map{|m| m.strip}.join(",") : page.body
|
102
|
-
raise "operation failed.detail=#{error}".toutf8
|
103
|
-
end
|
104
|
-
|
105
|
-
#ホスト名
|
106
|
-
attr :host_name, true
|
107
|
-
end
|
108
|
-
|
109
|
-
module FX
|
110
|
-
|
111
|
-
# 通貨ペア: 米ドル-円
|
112
|
-
USDJPY = :USDJPY
|
113
|
-
# 通貨ペア: ユーロ-円
|
114
|
-
EURJPY = :EURJPY
|
115
|
-
# 通貨ペア: イギリスポンド-円
|
116
|
-
GBPJPY = :GBPJPY
|
117
|
-
# 通貨ペア: 豪ドル-円
|
118
|
-
AUDJPY = :AUDJPY
|
119
|
-
# 通貨ペア: ニュージーランドドル-円
|
120
|
-
NZDJPY = :NZDJPY
|
121
|
-
# 通貨ペア: カナダドル-円
|
122
|
-
CADJPY = :CADJPY
|
123
|
-
# 通貨ペア: スイスフラン-円
|
124
|
-
CHFJPY = :CHFJPY
|
125
|
-
# 通貨ペア: 南アランド-円
|
126
|
-
ZARJPY = :ZARJPY
|
127
|
-
# 通貨ペア: ユーロ-米ドル
|
128
|
-
EURUSD = :EURUSD
|
129
|
-
# 通貨ペア: イギリスポンド-米ドル
|
130
|
-
GBPUSD = :GBPUSD
|
131
|
-
# 通貨ペア: 豪ドル-米ドル
|
132
|
-
AUDUSD = :AUDUSD
|
133
|
-
# 通貨ペア: ユーロ-スイスフラン
|
134
|
-
EURCHF = :EURCHF
|
135
|
-
# 通貨ペア: イギリスポンド-スイスフラン
|
136
|
-
GBPCHF = :GBPCHF
|
137
|
-
# 通貨ペア: 米ドル-スイスフラン
|
138
|
-
USDCHF = :USDCHF
|
139
|
-
|
140
|
-
# 売買区分: 買い
|
141
|
-
BUY = 0
|
142
|
-
# 売買区分: 売り
|
143
|
-
SELL = 1
|
144
|
-
|
145
|
-
# 注文タイプ: 通常
|
146
|
-
ORDER_TYPE_MARKET_ORDER = "00"
|
147
|
-
# 注文タイプ: 通常
|
148
|
-
ORDER_TYPE_NORMAL = "01"
|
149
|
-
# 注文タイプ: IFD
|
150
|
-
ORDER_TYPE_IFD = "11"
|
151
|
-
# 注文タイプ: OCO
|
152
|
-
ORDER_TYPE_OCO = "21"
|
153
|
-
# 注文タイプ: IFD-OCO
|
154
|
-
ORDER_TYPE_IFD_OCO = "31"
|
155
|
-
|
156
|
-
# 有効期限: 当日限り
|
157
|
-
EXPIRATION_TYPE_TODAY = 0
|
158
|
-
# 有効期限: 週末まで
|
159
|
-
EXPIRATION_TYPE_WEEK_END = 1
|
160
|
-
# 有効期限: 無期限
|
161
|
-
EXPIRATION_TYPE_INFINITY = 2
|
162
|
-
# 有効期限: 日付指定
|
163
|
-
EXPIRATION_TYPE_SPECIFIED = 3
|
164
|
-
|
165
|
-
# 注文状況: すべて
|
166
|
-
ORDER_CONDITION_ALL = ""
|
167
|
-
# 注文状況: 注文中
|
168
|
-
ORDER_CONDITION_ON_ORDER = "0"
|
169
|
-
# 注文状況: 取消済
|
170
|
-
ORDER_CONDITION_CANCELED = "1"
|
171
|
-
# 注文状況: 約定
|
172
|
-
ORDER_CONDITION_EXECUTION = "2"
|
173
|
-
# 注文状況: 不成立
|
174
|
-
ORDER_CONDITION_FAILED = "3"
|
175
|
-
|
176
|
-
# トレード種別: 新規
|
177
|
-
TRADE_TYPE_NEW = "新規"
|
178
|
-
# トレード種別: 決済
|
179
|
-
TRADE_TYPE_SETTLEMENT = "決済"
|
180
|
-
|
181
|
-
# 執行条件: 成行
|
182
|
-
EXECUTION_EXPRESSION_MARKET_ORDER = "成行"
|
183
|
-
# 執行条件: 指値
|
184
|
-
EXECUTION_EXPRESSION_LIMIT_ORDER = "指値"
|
185
|
-
# 執行条件: 逆指値
|
186
|
-
EXECUTION_EXPRESSION_REVERSE_LIMIT_ORDER = "逆指値"
|
187
|
-
|
188
|
-
#=== FX取引のためのセッションクラス
|
189
|
-
#Client#fx_sessionのブロックの引数として渡されます。詳細はClient#fx_sessionを参照ください。
|
190
|
-
class FxSession
|
191
|
-
|
192
|
-
def initialize( client, links, options={} )
|
193
|
-
@client = client
|
194
|
-
@links = links
|
195
|
-
@options = options
|
196
|
-
end
|
197
|
-
|
198
|
-
#レート一覧を取得します。
|
199
|
-
#
|
200
|
-
#戻り値:: 通貨ペアをキーとするClickClientScrap::FX::Rateのハッシュ。
|
201
|
-
def list_rates
|
202
|
-
result = link_click( "1" )
|
203
|
-
if !@last_update_time_of_swaps \
|
204
|
-
|| Time.now.to_i - @last_update_time_of_swaps > (@options[:swap_update_interval] || 60*60)
|
205
|
-
@swaps = list_swaps
|
206
|
-
@last_update_time_of_swaps = Time.now.to_i
|
207
|
-
end
|
208
|
-
reg = />([A-Z]+\/[A-Z]+)<\/a>[^\-\.\d]*?([\d]+\.[\d]+)\-[^\-\.\d]*([\d\.]+)/
|
209
|
-
tokens = result.body.toutf8.scan( reg )
|
210
|
-
ClickClientScrap::Client.error( result ) if !tokens || tokens.empty?
|
211
|
-
return tokens.inject({}) {|r,l|
|
212
|
-
pair = to_pair( l[0] )
|
213
|
-
swap = @swaps[pair]
|
214
|
-
rate = FxSession.convert_rate "#{l[1]}-#{l[2]}"
|
215
|
-
if ( rate && swap )
|
216
|
-
r[pair] = Rate.new( pair, rate[0], rate[1], swap.sell_swap, swap.buy_swap )
|
217
|
-
end
|
218
|
-
r
|
219
|
-
}
|
220
|
-
end
|
221
|
-
#12.34-35 形式の文字列をbidレート、askレートに変換する。
|
222
|
-
def self.convert_rate( str ) #:nodoc:
|
223
|
-
if str =~ /^([\d]+)\.([\d]+)\-([\d]+)$/
|
224
|
-
high = $1
|
225
|
-
low = $2
|
226
|
-
low2 = $3
|
227
|
-
bid = high.to_f+(low.to_f/(10**low.length))
|
228
|
-
ask_low = (low[0...low.length-low2.length] + low2).to_f
|
229
|
-
if low.to_f > ask_low
|
230
|
-
ask_low += 10**low2.length
|
231
|
-
end
|
232
|
-
ask = high.to_f+(ask_low/10**low.length)
|
233
|
-
return [bid,ask]
|
234
|
-
elsif str =~ /^([\d]+\.[\d]+)\-([\d]+\.[\d]+)$/
|
235
|
-
return [$1.to_f,$2.to_f]
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
#スワップの一覧を取得します。
|
240
|
-
#
|
241
|
-
#戻り値:: 通貨ペアをキーとするClickClientScrap::FX::Swapのハッシュ。
|
242
|
-
def list_swaps
|
243
|
-
result = link_click( "8" )
|
244
|
-
reg = /<dd>([A-Z]+\/[A-Z]+) <font[^>]*>売<\/font>[^\-\d]*?([\-\d,]+)[^\-\d]*<font[^>]*>買<\/font>[^\-\d]*([\-\d,]+)[^\-\d]*<\/dd>/
|
245
|
-
return result.body.toutf8.scan( reg ).inject({}) {|r,l|
|
246
|
-
pair = to_pair( l[0] )
|
247
|
-
r[pair] = Swap.new( pair, l[1].sub(/,/,"").to_i, l[2].sub(/,/,"").to_i ); r
|
248
|
-
}
|
249
|
-
end
|
250
|
-
|
251
|
-
#
|
252
|
-
#注文を行います。
|
253
|
-
#
|
254
|
-
#currency_pair_code:: 通貨ペアコード(必須)
|
255
|
-
#sell_or_buy:: 売買区分。ClickClientScrap::FX::BUY,ClickClientScrap::FX::SELLのいずれかを指定します。(必須)
|
256
|
-
#unit:: 取引数量(必須)
|
257
|
-
#options:: 注文のオプション。注文方法に応じて以下の情報を設定できます。
|
258
|
-
# - <b>成り行き注文</b>
|
259
|
-
# - <tt>:slippage</tt> .. スリッページ (オプション)。何pips以内かを整数で指定します。
|
260
|
-
# - <b>通常注文</b> ※注文レートが設定されていれば通常取引となります。
|
261
|
-
# - <tt>:rate</tt> .. 注文レート(必須)
|
262
|
-
# - <tt>:execution_expression</tt> .. 執行条件。ClickClientScrap::FX::EXECUTION_EXPRESSION_LIMIT_ORDER等を指定します(必須)
|
263
|
-
# - <tt>:expiration_type</tt> .. 有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
264
|
-
# - <tt>:expiration_date</tt> .. 有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
265
|
-
# - <b>OCO注文</b> ※逆指値レートが設定されていればOCO取引となります。
|
266
|
-
# - <tt>:rate</tt> .. 注文レート(必須)
|
267
|
-
# - <tt>:stop_order_rate</tt> .. 逆指値レート(必須)
|
268
|
-
# - <tt>:expiration_type</tt> .. 有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
269
|
-
# - <tt>:expiration_date</tt> .. 有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
270
|
-
# - <b>IFD注文</b> ※決済取引の指定があればIFD取引となります。
|
271
|
-
# - <tt>:rate</tt> .. 注文レート(必須)
|
272
|
-
# - <tt>:execution_expression</tt> .. 執行条件。ClickClientScrap::FX::EXECUTION_EXPRESSION_LIMIT_ORDER等を指定します(必須)
|
273
|
-
# - <tt>:expiration_type</tt> .. 有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
274
|
-
# - <tt>:expiration_date</tt> .. 有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
275
|
-
# - <tt>:settle</tt> .. 決済取引の指定。マップで指定します。
|
276
|
-
# - <tt>:unit</tt> .. 決済取引の取引数量(必須)
|
277
|
-
# - <tt>:sell_or_buy</tt> .. 決済取引の売買区分。ClickClientScrap::FX::BUY,ClickClientScrap::FX::SELLのいずれかを指定します。(必須)
|
278
|
-
# - <tt>:rate</tt> .. 決済取引の注文レート(必須)
|
279
|
-
# - <tt>:execution_expression</tt> .. 決済取引の執行条件。ClickClientScrap::FX::EXECUTION_EXPRESSION_LIMIT_ORDER等を指定します(必須)
|
280
|
-
# - <tt>:expiration_type</tt> .. 決済取引の有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
281
|
-
# - <tt>:expiration_date</tt> .. 決済取引の有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
282
|
-
# - <b>IFD-OCO注文</b> ※決済取引の指定と逆指値レートの指定があればIFD-OCO取引となります。
|
283
|
-
# - <tt>:rate</tt> .. 注文レート(必須)
|
284
|
-
# - <tt>:execution_expression</tt> .. 執行条件。ClickClientScrap::FX::EXECUTION_EXPRESSION_LIMIT_ORDER等を指定します(必須)
|
285
|
-
# - <tt>:expiration_type</tt> .. 有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
286
|
-
# - <tt>:expiration_date</tt> .. 有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
287
|
-
# - <tt>:settle</tt> .. 決済取引の指定。マップで指定します。
|
288
|
-
# - <tt>:unit</tt> .. 決済取引の取引数量(必須)
|
289
|
-
# - <tt>:sell_or_buy</tt> .. 決済取引の売買区分。ClickClientScrap::FX::BUY,ClickClientScrap::FX::SELLのいずれかを指定します。(必須)
|
290
|
-
# - <tt>:rate</tt> .. 決済取引の注文レート(必須)
|
291
|
-
# - <tt>:stop_order_rate</tt> .. 決済取引の逆指値レート(必須)
|
292
|
-
# - <tt>:expiration_type</tt> .. 決済取引の有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
293
|
-
# - <tt>:expiration_date</tt> .. 決済取引の有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
294
|
-
#戻り値:: ClickClientScrap::FX::OrderResult
|
295
|
-
#
|
296
|
-
def order ( currency_pair_code, sell_or_buy, unit, options={} )
|
297
|
-
|
298
|
-
# 取り引き種別の判別とパラメータチェック
|
299
|
-
type = ORDER_TYPE_MARKET_ORDER
|
300
|
-
if ( options && options[:settle] != nil )
|
301
|
-
if ( options[:settle][:stop_order_rate] != nil)
|
302
|
-
# 逆指値レートと決済取引の指定があればIFD-OCO取引
|
303
|
-
raise "options[:settle][:rate] is required." if options[:settle][:rate] == nil
|
304
|
-
type = ORDER_TYPE_IFD_OCO
|
305
|
-
else
|
306
|
-
# 決済取引の指定のみがあればIFD取引
|
307
|
-
raise "options[:settle][:rate] is required." if options[:settle][:rate] == nil
|
308
|
-
raise "options[:settle][:execution_expression] is required." if options[:settle][:execution_expression] == nil
|
309
|
-
type = ORDER_TYPE_IFD
|
310
|
-
end
|
311
|
-
raise "options[:rate] is required." if options[:rate] == nil
|
312
|
-
raise "options[:execution_expression] is required." if options[:execution_expression] == nil
|
313
|
-
raise "options[:expiration_type] is required." if options[:expiration_type] == nil
|
314
|
-
raise "options[:settle][:rate] is required." if options[:settle][:rate] == nil
|
315
|
-
raise "options[:settle][:sell_or_buy] is required." if options[:settle][:sell_or_buy] == nil
|
316
|
-
raise "options[:settle][:unit] is required." if options[:settle][:unit] == nil
|
317
|
-
raise "options[:settle][:expiration_type] is required." if options[:expiration_type] == nil
|
318
|
-
elsif ( options && options[:rate] != nil )
|
319
|
-
if ( options[:stop_order_rate] != nil )
|
320
|
-
# 逆指値レートが指定されていればOCO取引
|
321
|
-
type = ORDER_TYPE_OCO
|
322
|
-
else
|
323
|
-
# そうでなければ通常取引
|
324
|
-
raise "options[:execution_expression] is required." if options[:execution_expression] == nil
|
325
|
-
type = ORDER_TYPE_NORMAL
|
326
|
-
end
|
327
|
-
raise "options[:expiration_type] is required." if options[:expiration_type] == nil
|
328
|
-
else
|
329
|
-
# 成り行き
|
330
|
-
type = ORDER_TYPE_MARKET_ORDER
|
331
|
-
end
|
332
|
-
|
333
|
-
#注文前の注文一覧
|
334
|
-
before = list_orders( ORDER_CONDITION_ON_ORDER ).inject(Set.new) {|s,o| s << o[0]; s }
|
335
|
-
|
336
|
-
# レート一覧
|
337
|
-
result = link_click( "1" )
|
338
|
-
|
339
|
-
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
340
|
-
form = result.forms.first
|
341
|
-
|
342
|
-
# 通貨ペア
|
343
|
-
option = form.fields.find{|f| f.name == "P001" }.options.find {|o|
|
344
|
-
to_pair( o.text.strip ) == currency_pair_code
|
345
|
-
}
|
346
|
-
raise "illegal currency_pair_code. currency_pair_code=#{currency_pair_code.to_s}" unless option
|
347
|
-
option.select
|
348
|
-
|
349
|
-
#注文方式
|
350
|
-
form["P100"] = type
|
351
|
-
|
352
|
-
# 詳細設定画面へ
|
353
|
-
result = @client.submit(form)
|
354
|
-
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
355
|
-
form = result.forms.first
|
356
|
-
case type
|
357
|
-
when ORDER_TYPE_MARKET_ORDER
|
358
|
-
# 成り行き
|
359
|
-
form["P003"] = unit.to_s # 取り引き数量
|
360
|
-
form["P002.0"] = sell_or_buy == ClickClientScrap::FX::SELL ? "1" : "0" #売り/買い
|
361
|
-
form["P005"] = options[:slippage].to_s if ( options && options[:slippage] != nil ) # スリッページ
|
362
|
-
when ORDER_TYPE_NORMAL
|
363
|
-
# 指値
|
364
|
-
form["P003"] = options[:rate].to_s # レート
|
365
|
-
form["P005"] = unit.to_s # 取り引き数量
|
366
|
-
form["P002.0"] = sell_or_buy == ClickClientScrap::FX::SELL ? "1" : "0" #売り/買い
|
367
|
-
exp = options[:execution_expression]
|
368
|
-
form["P004.0"] = exp == ClickClientScrap::FX::EXECUTION_EXPRESSION_REVERSE_LIMIT_ORDER ? "2" : "1" #指値/逆指値
|
369
|
-
set_expiration( form, options, "P008", "P009" ) # 有効期限
|
370
|
-
when ORDER_TYPE_OCO
|
371
|
-
# OCO
|
372
|
-
form["P003"] = options[:rate].to_s # レート
|
373
|
-
form["P005"] = options[:stop_order_rate].to_s # 逆指値レート
|
374
|
-
form["P007"] = unit.to_s # 取り引き数量
|
375
|
-
form["P002.0"] = sell_or_buy == ClickClientScrap::FX::SELL ? "1" : "0" #売り/買い
|
376
|
-
set_expiration( form, options, "P010", "P011" ) # 有効期限
|
377
|
-
else
|
378
|
-
raise "not supported yet."
|
379
|
-
end
|
380
|
-
|
381
|
-
# 確認画面へ
|
382
|
-
result = @client.submit(form)
|
383
|
-
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
384
|
-
result = @client.submit(result.forms.first)
|
385
|
-
ClickClientScrap::Client.error( result ) unless result.body.toutf8 =~ /注文受付完了/
|
386
|
-
|
387
|
-
#注文前の一覧と注文後の一覧を比較して注文を割り出す。
|
388
|
-
#成り行き注文の場合、即座に約定するのでnilになる(タイミングによっては取得できるかも)
|
389
|
-
tmp = list_orders( ORDER_CONDITION_ON_ORDER ).find {|o| !before.include?(o[0]) }
|
390
|
-
return OrderResult.new( tmp ? tmp[1].order_no : nil )
|
391
|
-
end
|
392
|
-
|
393
|
-
# 有効期限を設定する
|
394
|
-
#form:: フォーム
|
395
|
-
#options:: パラメータ
|
396
|
-
#input_type:: 有効期限の種別を入力するinput要素名
|
397
|
-
#input_date:: 有効期限が日付指定の場合に、日付を入力するinput要素名
|
398
|
-
def set_expiration( form, options, input_type, input_date )
|
399
|
-
case options[:expiration_type]
|
400
|
-
when ClickClientScrap::FX::EXPIRATION_TYPE_TODAY
|
401
|
-
form[input_type] = "0"
|
402
|
-
when ClickClientScrap::FX::EXPIRATION_TYPE_WEEK_END
|
403
|
-
form[input_type] = "1"
|
404
|
-
when ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED
|
405
|
-
form[input_type] = "3"
|
406
|
-
raise "options[:expiration_date] is required." unless options[:expiration_date]
|
407
|
-
form["#{input_date}.Y"] = options[:expiration_date].year
|
408
|
-
form["#{input_date}.M"] = options[:expiration_date].month
|
409
|
-
form["#{input_date}.D"] = options[:expiration_date].day
|
410
|
-
form["#{input_date}.h"] = options[:expiration_date].respond_to?(:hour) ? options[:expiration_date].hour : "0"
|
411
|
-
else
|
412
|
-
form[input_type] = "2"
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
#
|
417
|
-
#=== 注文をキャンセルします。
|
418
|
-
#
|
419
|
-
#order_no:: 注文番号
|
420
|
-
#戻り値:: なし
|
421
|
-
#
|
422
|
-
def cancel_order( order_no )
|
423
|
-
|
424
|
-
raise "order_no is nil." unless order_no
|
425
|
-
|
426
|
-
# 注文一覧
|
427
|
-
result = link_click( "2" )
|
428
|
-
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
429
|
-
form = result.forms.first
|
430
|
-
form["P002"] = ORDER_CONDITION_ON_ORDER
|
431
|
-
result = @client.submit(form)
|
432
|
-
|
433
|
-
# 対象となる注文をクリック
|
434
|
-
link =
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
result
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
#
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
#
|
462
|
-
# - <tt>:
|
463
|
-
# - <tt>:
|
464
|
-
#
|
465
|
-
#
|
466
|
-
# - <tt>:
|
467
|
-
# - <tt>:
|
468
|
-
# - <tt>:
|
469
|
-
#
|
470
|
-
|
471
|
-
#
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
raise "options[:expiration_type] is required." if options[:expiration_type] == nil
|
480
|
-
|
481
|
-
#
|
482
|
-
if
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
form
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
71
|
+
#戻り値:: ClickClientScrap::FX::FxSession
|
72
|
+
def fx_session( userid, password, options={}, &block )
|
73
|
+
page = @client.get(@host_name)
|
74
|
+
ClickClientScrap::Client.error(page) if page.forms.length <= 0
|
75
|
+
form = page.forms.first
|
76
|
+
form.j_username = userid
|
77
|
+
form.j_password = password
|
78
|
+
result = @client.submit(form, form.buttons.first)
|
79
|
+
# デモサイトではjsによるリダイレクトは不要。
|
80
|
+
if !@demo
|
81
|
+
if result.body.toutf8 =~ /<META HTTP-EQUIV="REFRESH" CONTENT="0;URL=([^"]*)">/
|
82
|
+
result = @client.get($1)
|
83
|
+
ClickClientScrap::Client.error( result ) if result.links.size <= 0
|
84
|
+
else
|
85
|
+
ClickClientScrap::Client.error( result )
|
86
|
+
end
|
87
|
+
end
|
88
|
+
session = FX::FxSession.new( @client, result.links, options )
|
89
|
+
if block_given?
|
90
|
+
begin
|
91
|
+
yield session
|
92
|
+
ensure
|
93
|
+
session.logout
|
94
|
+
end
|
95
|
+
else
|
96
|
+
return session
|
97
|
+
end
|
98
|
+
end
|
99
|
+
def self.error( page )
|
100
|
+
msgs = page.body.scan( /<font color="red">([^<]*)</ ).flatten
|
101
|
+
error = !msgs.empty? ? msgs.map{|m| m.strip}.join(",") : page.body
|
102
|
+
raise "operation failed.detail=#{error}".toutf8
|
103
|
+
end
|
104
|
+
|
105
|
+
#ホスト名
|
106
|
+
attr :host_name, true
|
107
|
+
end
|
108
|
+
|
109
|
+
module FX
|
110
|
+
|
111
|
+
# 通貨ペア: 米ドル-円
|
112
|
+
USDJPY = :USDJPY
|
113
|
+
# 通貨ペア: ユーロ-円
|
114
|
+
EURJPY = :EURJPY
|
115
|
+
# 通貨ペア: イギリスポンド-円
|
116
|
+
GBPJPY = :GBPJPY
|
117
|
+
# 通貨ペア: 豪ドル-円
|
118
|
+
AUDJPY = :AUDJPY
|
119
|
+
# 通貨ペア: ニュージーランドドル-円
|
120
|
+
NZDJPY = :NZDJPY
|
121
|
+
# 通貨ペア: カナダドル-円
|
122
|
+
CADJPY = :CADJPY
|
123
|
+
# 通貨ペア: スイスフラン-円
|
124
|
+
CHFJPY = :CHFJPY
|
125
|
+
# 通貨ペア: 南アランド-円
|
126
|
+
ZARJPY = :ZARJPY
|
127
|
+
# 通貨ペア: ユーロ-米ドル
|
128
|
+
EURUSD = :EURUSD
|
129
|
+
# 通貨ペア: イギリスポンド-米ドル
|
130
|
+
GBPUSD = :GBPUSD
|
131
|
+
# 通貨ペア: 豪ドル-米ドル
|
132
|
+
AUDUSD = :AUDUSD
|
133
|
+
# 通貨ペア: ユーロ-スイスフラン
|
134
|
+
EURCHF = :EURCHF
|
135
|
+
# 通貨ペア: イギリスポンド-スイスフラン
|
136
|
+
GBPCHF = :GBPCHF
|
137
|
+
# 通貨ペア: 米ドル-スイスフラン
|
138
|
+
USDCHF = :USDCHF
|
139
|
+
|
140
|
+
# 売買区分: 買い
|
141
|
+
BUY = 0
|
142
|
+
# 売買区分: 売り
|
143
|
+
SELL = 1
|
144
|
+
|
145
|
+
# 注文タイプ: 通常
|
146
|
+
ORDER_TYPE_MARKET_ORDER = "00"
|
147
|
+
# 注文タイプ: 通常
|
148
|
+
ORDER_TYPE_NORMAL = "01"
|
149
|
+
# 注文タイプ: IFD
|
150
|
+
ORDER_TYPE_IFD = "11"
|
151
|
+
# 注文タイプ: OCO
|
152
|
+
ORDER_TYPE_OCO = "21"
|
153
|
+
# 注文タイプ: IFD-OCO
|
154
|
+
ORDER_TYPE_IFD_OCO = "31"
|
155
|
+
|
156
|
+
# 有効期限: 当日限り
|
157
|
+
EXPIRATION_TYPE_TODAY = 0
|
158
|
+
# 有効期限: 週末まで
|
159
|
+
EXPIRATION_TYPE_WEEK_END = 1
|
160
|
+
# 有効期限: 無期限
|
161
|
+
EXPIRATION_TYPE_INFINITY = 2
|
162
|
+
# 有効期限: 日付指定
|
163
|
+
EXPIRATION_TYPE_SPECIFIED = 3
|
164
|
+
|
165
|
+
# 注文状況: すべて
|
166
|
+
ORDER_CONDITION_ALL = ""
|
167
|
+
# 注文状況: 注文中
|
168
|
+
ORDER_CONDITION_ON_ORDER = "0"
|
169
|
+
# 注文状況: 取消済
|
170
|
+
ORDER_CONDITION_CANCELED = "1"
|
171
|
+
# 注文状況: 約定
|
172
|
+
ORDER_CONDITION_EXECUTION = "2"
|
173
|
+
# 注文状況: 不成立
|
174
|
+
ORDER_CONDITION_FAILED = "3"
|
175
|
+
|
176
|
+
# トレード種別: 新規
|
177
|
+
TRADE_TYPE_NEW = "新規"
|
178
|
+
# トレード種別: 決済
|
179
|
+
TRADE_TYPE_SETTLEMENT = "決済"
|
180
|
+
|
181
|
+
# 執行条件: 成行
|
182
|
+
EXECUTION_EXPRESSION_MARKET_ORDER = "成行"
|
183
|
+
# 執行条件: 指値
|
184
|
+
EXECUTION_EXPRESSION_LIMIT_ORDER = "指値"
|
185
|
+
# 執行条件: 逆指値
|
186
|
+
EXECUTION_EXPRESSION_REVERSE_LIMIT_ORDER = "逆指値"
|
187
|
+
|
188
|
+
#=== FX取引のためのセッションクラス
|
189
|
+
#Client#fx_sessionのブロックの引数として渡されます。詳細はClient#fx_sessionを参照ください。
|
190
|
+
class FxSession
|
191
|
+
|
192
|
+
def initialize( client, links, options={} )
|
193
|
+
@client = client
|
194
|
+
@links = links
|
195
|
+
@options = options
|
196
|
+
end
|
197
|
+
|
198
|
+
#レート一覧を取得します。
|
199
|
+
#
|
200
|
+
#戻り値:: 通貨ペアをキーとするClickClientScrap::FX::Rateのハッシュ。
|
201
|
+
def list_rates
|
202
|
+
result = link_click( "1" )
|
203
|
+
if !@last_update_time_of_swaps \
|
204
|
+
|| Time.now.to_i - @last_update_time_of_swaps > (@options[:swap_update_interval] || 60*60)
|
205
|
+
@swaps = list_swaps
|
206
|
+
@last_update_time_of_swaps = Time.now.to_i
|
207
|
+
end
|
208
|
+
reg = />([A-Z]+\/[A-Z]+)<\/a>[^\-\.\d]*?([\d]+\.[\d]+)\-[^\-\.\d]*([\d\.]+)/
|
209
|
+
tokens = result.body.toutf8.scan( reg )
|
210
|
+
ClickClientScrap::Client.error( result ) if !tokens || tokens.empty?
|
211
|
+
return tokens.inject({}) {|r,l|
|
212
|
+
pair = to_pair( l[0] )
|
213
|
+
swap = @swaps[pair]
|
214
|
+
rate = FxSession.convert_rate "#{l[1]}-#{l[2]}"
|
215
|
+
if ( rate && swap )
|
216
|
+
r[pair] = Rate.new( pair, rate[0], rate[1], swap.sell_swap, swap.buy_swap )
|
217
|
+
end
|
218
|
+
r
|
219
|
+
}
|
220
|
+
end
|
221
|
+
#12.34-35 形式の文字列をbidレート、askレートに変換する。
|
222
|
+
def self.convert_rate( str ) #:nodoc:
|
223
|
+
if str =~ /^([\d]+)\.([\d]+)\-([\d]+)$/
|
224
|
+
high = $1
|
225
|
+
low = $2
|
226
|
+
low2 = $3
|
227
|
+
bid = high.to_f+(low.to_f/(10**low.length))
|
228
|
+
ask_low = (low[0...low.length-low2.length] + low2).to_f
|
229
|
+
if low.to_f > ask_low
|
230
|
+
ask_low += 10**low2.length
|
231
|
+
end
|
232
|
+
ask = high.to_f+(ask_low/10**low.length)
|
233
|
+
return [bid,ask]
|
234
|
+
elsif str =~ /^([\d]+\.[\d]+)\-([\d]+\.[\d]+)$/
|
235
|
+
return [$1.to_f,$2.to_f]
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
#スワップの一覧を取得します。
|
240
|
+
#
|
241
|
+
#戻り値:: 通貨ペアをキーとするClickClientScrap::FX::Swapのハッシュ。
|
242
|
+
def list_swaps
|
243
|
+
result = link_click( "8" )
|
244
|
+
reg = /<dd>([A-Z]+\/[A-Z]+) <font[^>]*>売<\/font>[^\-\d]*?([\-\d,]+)[^\-\d]*<font[^>]*>買<\/font>[^\-\d]*([\-\d,]+)[^\-\d]*<\/dd>/
|
245
|
+
return result.body.toutf8.scan( reg ).inject({}) {|r,l|
|
246
|
+
pair = to_pair( l[0] )
|
247
|
+
r[pair] = Swap.new( pair, l[1].sub(/,/,"").to_i, l[2].sub(/,/,"").to_i ); r
|
248
|
+
}
|
249
|
+
end
|
250
|
+
|
251
|
+
#
|
252
|
+
#注文を行います。
|
253
|
+
#
|
254
|
+
#currency_pair_code:: 通貨ペアコード(必須)
|
255
|
+
#sell_or_buy:: 売買区分。ClickClientScrap::FX::BUY,ClickClientScrap::FX::SELLのいずれかを指定します。(必須)
|
256
|
+
#unit:: 取引数量(必須)
|
257
|
+
#options:: 注文のオプション。注文方法に応じて以下の情報を設定できます。
|
258
|
+
# - <b>成り行き注文</b>
|
259
|
+
# - <tt>:slippage</tt> .. スリッページ (オプション)。何pips以内かを整数で指定します。
|
260
|
+
# - <b>通常注文</b> ※注文レートが設定されていれば通常取引となります。
|
261
|
+
# - <tt>:rate</tt> .. 注文レート(必須)
|
262
|
+
# - <tt>:execution_expression</tt> .. 執行条件。ClickClientScrap::FX::EXECUTION_EXPRESSION_LIMIT_ORDER等を指定します(必須)
|
263
|
+
# - <tt>:expiration_type</tt> .. 有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
264
|
+
# - <tt>:expiration_date</tt> .. 有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
265
|
+
# - <b>OCO注文</b> ※逆指値レートが設定されていればOCO取引となります。
|
266
|
+
# - <tt>:rate</tt> .. 注文レート(必須)
|
267
|
+
# - <tt>:stop_order_rate</tt> .. 逆指値レート(必須)
|
268
|
+
# - <tt>:expiration_type</tt> .. 有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
269
|
+
# - <tt>:expiration_date</tt> .. 有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
270
|
+
# - <b>IFD注文</b> ※決済取引の指定があればIFD取引となります。
|
271
|
+
# - <tt>:rate</tt> .. 注文レート(必須)
|
272
|
+
# - <tt>:execution_expression</tt> .. 執行条件。ClickClientScrap::FX::EXECUTION_EXPRESSION_LIMIT_ORDER等を指定します(必須)
|
273
|
+
# - <tt>:expiration_type</tt> .. 有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
274
|
+
# - <tt>:expiration_date</tt> .. 有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
275
|
+
# - <tt>:settle</tt> .. 決済取引の指定。マップで指定します。
|
276
|
+
# - <tt>:unit</tt> .. 決済取引の取引数量(必須)
|
277
|
+
# - <tt>:sell_or_buy</tt> .. 決済取引の売買区分。ClickClientScrap::FX::BUY,ClickClientScrap::FX::SELLのいずれかを指定します。(必須)
|
278
|
+
# - <tt>:rate</tt> .. 決済取引の注文レート(必須)
|
279
|
+
# - <tt>:execution_expression</tt> .. 決済取引の執行条件。ClickClientScrap::FX::EXECUTION_EXPRESSION_LIMIT_ORDER等を指定します(必須)
|
280
|
+
# - <tt>:expiration_type</tt> .. 決済取引の有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
281
|
+
# - <tt>:expiration_date</tt> .. 決済取引の有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
282
|
+
# - <b>IFD-OCO注文</b> ※決済取引の指定と逆指値レートの指定があればIFD-OCO取引となります。
|
283
|
+
# - <tt>:rate</tt> .. 注文レート(必須)
|
284
|
+
# - <tt>:execution_expression</tt> .. 執行条件。ClickClientScrap::FX::EXECUTION_EXPRESSION_LIMIT_ORDER等を指定します(必須)
|
285
|
+
# - <tt>:expiration_type</tt> .. 有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
286
|
+
# - <tt>:expiration_date</tt> .. 有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
287
|
+
# - <tt>:settle</tt> .. 決済取引の指定。マップで指定します。
|
288
|
+
# - <tt>:unit</tt> .. 決済取引の取引数量(必須)
|
289
|
+
# - <tt>:sell_or_buy</tt> .. 決済取引の売買区分。ClickClientScrap::FX::BUY,ClickClientScrap::FX::SELLのいずれかを指定します。(必須)
|
290
|
+
# - <tt>:rate</tt> .. 決済取引の注文レート(必須)
|
291
|
+
# - <tt>:stop_order_rate</tt> .. 決済取引の逆指値レート(必須)
|
292
|
+
# - <tt>:expiration_type</tt> .. 決済取引の有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
293
|
+
# - <tt>:expiration_date</tt> .. 決済取引の有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
294
|
+
#戻り値:: ClickClientScrap::FX::OrderResult
|
295
|
+
#
|
296
|
+
def order ( currency_pair_code, sell_or_buy, unit, options={} )
|
297
|
+
|
298
|
+
# 取り引き種別の判別とパラメータチェック
|
299
|
+
type = ORDER_TYPE_MARKET_ORDER
|
300
|
+
if ( options && options[:settle] != nil )
|
301
|
+
if ( options[:settle][:stop_order_rate] != nil)
|
302
|
+
# 逆指値レートと決済取引の指定があればIFD-OCO取引
|
303
|
+
raise "options[:settle][:rate] is required." if options[:settle][:rate] == nil
|
304
|
+
type = ORDER_TYPE_IFD_OCO
|
305
|
+
else
|
306
|
+
# 決済取引の指定のみがあればIFD取引
|
307
|
+
raise "options[:settle][:rate] is required." if options[:settle][:rate] == nil
|
308
|
+
raise "options[:settle][:execution_expression] is required." if options[:settle][:execution_expression] == nil
|
309
|
+
type = ORDER_TYPE_IFD
|
310
|
+
end
|
311
|
+
raise "options[:rate] is required." if options[:rate] == nil
|
312
|
+
raise "options[:execution_expression] is required." if options[:execution_expression] == nil
|
313
|
+
raise "options[:expiration_type] is required." if options[:expiration_type] == nil
|
314
|
+
raise "options[:settle][:rate] is required." if options[:settle][:rate] == nil
|
315
|
+
raise "options[:settle][:sell_or_buy] is required." if options[:settle][:sell_or_buy] == nil
|
316
|
+
raise "options[:settle][:unit] is required." if options[:settle][:unit] == nil
|
317
|
+
raise "options[:settle][:expiration_type] is required." if options[:expiration_type] == nil
|
318
|
+
elsif ( options && options[:rate] != nil )
|
319
|
+
if ( options[:stop_order_rate] != nil )
|
320
|
+
# 逆指値レートが指定されていればOCO取引
|
321
|
+
type = ORDER_TYPE_OCO
|
322
|
+
else
|
323
|
+
# そうでなければ通常取引
|
324
|
+
raise "options[:execution_expression] is required." if options[:execution_expression] == nil
|
325
|
+
type = ORDER_TYPE_NORMAL
|
326
|
+
end
|
327
|
+
raise "options[:expiration_type] is required." if options[:expiration_type] == nil
|
328
|
+
else
|
329
|
+
# 成り行き
|
330
|
+
type = ORDER_TYPE_MARKET_ORDER
|
331
|
+
end
|
332
|
+
|
333
|
+
#注文前の注文一覧
|
334
|
+
before = list_orders( ORDER_CONDITION_ON_ORDER ).inject(Set.new) {|s,o| s << o[0]; s }
|
335
|
+
|
336
|
+
# レート一覧
|
337
|
+
result = link_click( "1" )
|
338
|
+
|
339
|
+
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
340
|
+
form = result.forms.first
|
341
|
+
|
342
|
+
# 通貨ペア
|
343
|
+
option = form.fields.find{|f| f.name == "P001" }.options.find {|o|
|
344
|
+
to_pair( o.text.strip ) == currency_pair_code
|
345
|
+
}
|
346
|
+
raise "illegal currency_pair_code. currency_pair_code=#{currency_pair_code.to_s}" unless option
|
347
|
+
option.select
|
348
|
+
|
349
|
+
#注文方式
|
350
|
+
form["P100"] = type
|
351
|
+
|
352
|
+
# 詳細設定画面へ
|
353
|
+
result = @client.submit(form)
|
354
|
+
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
355
|
+
form = result.forms.first
|
356
|
+
case type
|
357
|
+
when ORDER_TYPE_MARKET_ORDER
|
358
|
+
# 成り行き
|
359
|
+
form["P003"] = unit.to_s # 取り引き数量
|
360
|
+
form["P002.0"] = sell_or_buy == ClickClientScrap::FX::SELL ? "1" : "0" #売り/買い
|
361
|
+
form["P005"] = options[:slippage].to_s if ( options && options[:slippage] != nil ) # スリッページ
|
362
|
+
when ORDER_TYPE_NORMAL
|
363
|
+
# 指値
|
364
|
+
form["P003"] = options[:rate].to_s # レート
|
365
|
+
form["P005"] = unit.to_s # 取り引き数量
|
366
|
+
form["P002.0"] = sell_or_buy == ClickClientScrap::FX::SELL ? "1" : "0" #売り/買い
|
367
|
+
exp = options[:execution_expression]
|
368
|
+
form["P004.0"] = exp == ClickClientScrap::FX::EXECUTION_EXPRESSION_REVERSE_LIMIT_ORDER ? "2" : "1" #指値/逆指値
|
369
|
+
set_expiration( form, options, "P008", "P009" ) # 有効期限
|
370
|
+
when ORDER_TYPE_OCO
|
371
|
+
# OCO
|
372
|
+
form["P003"] = options[:rate].to_s # レート
|
373
|
+
form["P005"] = options[:stop_order_rate].to_s # 逆指値レート
|
374
|
+
form["P007"] = unit.to_s # 取り引き数量
|
375
|
+
form["P002.0"] = sell_or_buy == ClickClientScrap::FX::SELL ? "1" : "0" #売り/買い
|
376
|
+
set_expiration( form, options, "P010", "P011" ) # 有効期限
|
377
|
+
else
|
378
|
+
raise "not supported yet."
|
379
|
+
end
|
380
|
+
|
381
|
+
# 確認画面へ
|
382
|
+
result = @client.submit(form)
|
383
|
+
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
384
|
+
result = @client.submit(result.forms.first)
|
385
|
+
ClickClientScrap::Client.error( result ) unless result.body.toutf8 =~ /注文受付完了/
|
386
|
+
|
387
|
+
#注文前の一覧と注文後の一覧を比較して注文を割り出す。
|
388
|
+
#成り行き注文の場合、即座に約定するのでnilになる(タイミングによっては取得できるかも)
|
389
|
+
tmp = list_orders( ORDER_CONDITION_ON_ORDER ).find {|o| !before.include?(o[0]) }
|
390
|
+
return OrderResult.new( tmp ? tmp[1].order_no : nil )
|
391
|
+
end
|
392
|
+
|
393
|
+
# 有効期限を設定する
|
394
|
+
#form:: フォーム
|
395
|
+
#options:: パラメータ
|
396
|
+
#input_type:: 有効期限の種別を入力するinput要素名
|
397
|
+
#input_date:: 有効期限が日付指定の場合に、日付を入力するinput要素名
|
398
|
+
def set_expiration( form, options, input_type, input_date )
|
399
|
+
case options[:expiration_type]
|
400
|
+
when ClickClientScrap::FX::EXPIRATION_TYPE_TODAY
|
401
|
+
form[input_type] = "0"
|
402
|
+
when ClickClientScrap::FX::EXPIRATION_TYPE_WEEK_END
|
403
|
+
form[input_type] = "1"
|
404
|
+
when ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED
|
405
|
+
form[input_type] = "3"
|
406
|
+
raise "options[:expiration_date] is required." unless options[:expiration_date]
|
407
|
+
form["#{input_date}.Y"] = options[:expiration_date].year
|
408
|
+
form["#{input_date}.M"] = options[:expiration_date].month
|
409
|
+
form["#{input_date}.D"] = options[:expiration_date].day
|
410
|
+
form["#{input_date}.h"] = options[:expiration_date].respond_to?(:hour) ? options[:expiration_date].hour : "0"
|
411
|
+
else
|
412
|
+
form[input_type] = "2"
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
#
|
417
|
+
#=== 注文をキャンセルします。
|
418
|
+
#
|
419
|
+
#order_no:: 注文番号
|
420
|
+
#戻り値:: なし
|
421
|
+
#
|
422
|
+
def cancel_order( order_no )
|
423
|
+
|
424
|
+
raise "order_no is nil." unless order_no
|
425
|
+
|
426
|
+
# 注文一覧
|
427
|
+
result = link_click( "2" )
|
428
|
+
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
429
|
+
form = result.forms.first
|
430
|
+
form["P002"] = ORDER_CONDITION_ON_ORDER
|
431
|
+
result = @client.submit(form)
|
432
|
+
|
433
|
+
# 対象となる注文をクリック
|
434
|
+
link = nil
|
435
|
+
each_page( result ) {|page|
|
436
|
+
link = page.links.find {|l|
|
437
|
+
l.href =~ /[^"]*GKEY=([a-zA-Z0-9]*)[^"]*/ && $1 == order_no
|
438
|
+
}
|
439
|
+
break if link
|
440
|
+
}
|
441
|
+
raise "illegal order_no. order_no=#{order_no}" unless link
|
442
|
+
result = @client.click(link)
|
443
|
+
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
444
|
+
|
445
|
+
# キャンセル
|
446
|
+
form = result.forms[1]
|
447
|
+
result = @client.submit(form)
|
448
|
+
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
449
|
+
form = result.forms.first
|
450
|
+
result = @client.submit(form)
|
451
|
+
ClickClientScrap::Client.error( result ) unless result.body.toutf8 =~ /注文取消受付完了/
|
452
|
+
end
|
453
|
+
|
454
|
+
|
455
|
+
#
|
456
|
+
#=== 決済注文を行います。
|
457
|
+
#
|
458
|
+
#*open_interest_id*:: 決済する建玉番号
|
459
|
+
#*unit*:: 取引数量
|
460
|
+
#*options*:: 決済注文のオプション。注文方法に応じて以下の情報を設定できます。
|
461
|
+
# - <b>成り行き注文</b>
|
462
|
+
# - <tt>:slippage</tt> .. スリッページ (オプション)
|
463
|
+
# - <tt>:slippage_base_rate</tt> .. スリッページの基準となる取引レート(スリッページが指定された場合、必須。)
|
464
|
+
# - <b>通常注文</b> <b>※未実装</b> ※注文レートが設定されていれば通常取引となります。
|
465
|
+
# - <tt>:rate</tt> .. 注文レート(必須)
|
466
|
+
# - <tt>:execution_expression</tt> .. 執行条件。ClickClientScrap::FX::EXECUTION_EXPRESSION_LIMIT_ORDER等を指定します(必須)
|
467
|
+
# - <tt>:expiration_type</tt> .. 有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
468
|
+
# - <tt>:expiration_date</tt> .. 有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
469
|
+
# - <b>OCO注文</b> <b>※未実装</b> ※注文レートと逆指値レートが設定されていればOCO取引となります。
|
470
|
+
# - <tt>:rate</tt> .. 注文レート(必須)
|
471
|
+
# - <tt>:stop_order_rate</tt> .. 逆指値レート(必須)
|
472
|
+
# - <tt>:expiration_type</tt> .. 有効期限。ClickClientScrap::FX::EXPIRATION_TYPE_TODAY等を指定します(必須)
|
473
|
+
# - <tt>:expiration_date</tt> .. 有効期限が「日付指定(ClickClientScrap::FX::EXPIRATION_TYPE_SPECIFIED)」の場合の有効期限をDateで指定します。(有効期限が「日付指定」の場合、必須)
|
474
|
+
#<b>戻り値</b>:: なし
|
475
|
+
#
|
476
|
+
def settle ( open_interest_id, unit, options={} )
|
477
|
+
if ( options[:rate] != nil && options[:stop_order_rate] != nil )
|
478
|
+
# レートと逆指値レートが指定されていればOCO取引
|
479
|
+
raise "options[:expiration_type] is required." if options[:expiration_type] == nil
|
480
|
+
elsif ( options[:rate] != nil )
|
481
|
+
# レートが指定されていれば通常取引
|
482
|
+
raise "options[:execution_expression] is required." if options[:execution_expression] == nil
|
483
|
+
raise "options[:expiration_type] is required." if options[:expiration_type] == nil
|
484
|
+
else
|
485
|
+
# 成り行き
|
486
|
+
if ( options[:slippage] != nil )
|
487
|
+
raise "if you use a slippage, options[:slippage_base_rate] is required." if options[:slippage_base_rate] == nil
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
# 建玉一覧
|
492
|
+
result = link_click( "3" )
|
493
|
+
|
494
|
+
# 対象となる建玉をクリック
|
495
|
+
link = nil
|
496
|
+
each_page( result ) {|page|
|
497
|
+
link = page.links.find {|l|
|
498
|
+
l.href =~ /[^"]*ORDERNO=([a-zA-Z0-9]*)[^"]*/ && $1 == open_interest_id
|
499
|
+
}
|
500
|
+
break if link
|
501
|
+
}
|
502
|
+
raise "illegal open_interest_id. open_interest_id=#{open_interest_id}" unless link
|
503
|
+
result = @client.click(link)
|
504
|
+
|
505
|
+
# 決済
|
506
|
+
form = result.forms.first
|
507
|
+
form["P100"] = "00" # 成り行き TODO 通常(01),OCO取引(21)対応
|
508
|
+
result = @client.submit(form)
|
509
|
+
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
510
|
+
|
511
|
+
# 設定
|
512
|
+
form = result.forms.first
|
513
|
+
form["P003"] = unit.to_s
|
514
|
+
form["P005"] = options[:slippage].to_s if options[:slippage]
|
515
|
+
result = @client.submit(form)
|
516
|
+
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
517
|
+
|
518
|
+
# 確認
|
519
|
+
form = result.forms.first
|
520
|
+
result = @client.submit(form)
|
521
|
+
ClickClientScrap::Client.error( result ) unless result.body.toutf8 =~ /完了/
|
522
|
+
end
|
523
|
+
|
524
|
+
|
525
|
+
#
|
526
|
+
#=== 注文一覧を取得します。
|
527
|
+
#
|
528
|
+
#order_condition_code:: 注文状況コード(必須)
|
529
|
+
#currency_pair_code:: 通貨ペアコード <b>※未実装</b>
|
530
|
+
#戻り値:: 注文番号をキーとするClickClientScrap::FX::Orderのハッシュ。
|
531
|
+
#
|
532
|
+
def list_orders( order_condition_code=ClickClientScrap::FX::ORDER_CONDITION_ALL, currency_pair_code=nil )
|
533
|
+
result = link_click( "2" )
|
534
|
+
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
535
|
+
form = result.forms.first
|
536
|
+
form["P001"] = "" # TODO currency_pair_codeでの絞り込み
|
537
|
+
form["P002"] = order_condition_code
|
538
|
+
result = @client.submit(form)
|
539
|
+
|
540
|
+
list = []
|
541
|
+
each_page( result ) {|page|
|
542
|
+
list += page.body.toutf8.scan( /<a href="[^"]*GKEY=([a-zA-Z0-9]*)">([A-Z]{3}\/[A-Z]{3}) ([^<]*)<\/a><br>[^;]*;([^<]*)<font[^>]*>([^<]*)<\/font>([^@]*)@([\d\.]*)([^\s]*) ([^<]*)<br>([^;]*;([^<]*)<font[^>]*>([^<]*)<\/font>([^@]*)@([\d\.]*)([^\s]*) ([^<]*)<br>)?/m )
|
543
|
+
}
|
544
|
+
tmp = {}
|
545
|
+
list.each {|i|
|
546
|
+
order_no = i[0]
|
547
|
+
order_type = to_order_type_code(i[2])
|
548
|
+
trade_type = i[3] == "新" ? ClickClientScrap::FX::TRADE_TYPE_NEW \
|
549
|
+
: ClickClientScrap::FX::TRADE_TYPE_SETTLEMENT
|
550
|
+
pair = to_pair( i[1] )
|
551
|
+
sell_or_buy = i[4] == "売" ? ClickClientScrap::FX::SELL : ClickClientScrap::FX::BUY
|
552
|
+
count = pair == :ZARJPY ? i[5].to_i/10 : i[5].to_i
|
553
|
+
rate = i[6].to_f
|
554
|
+
execution_expression = to_execution_expression(i[7])
|
555
|
+
stop_order_rate = i[13] ? i[13].to_f : nil
|
556
|
+
stop_order_execution_expression = i[14] ? to_execution_expression(i[14]) : nil
|
557
|
+
|
558
|
+
tmp[order_no] = Order.new( order_no, trade_type, order_type, execution_expression, \
|
559
|
+
sell_or_buy, pair, count, rate, i[8], stop_order_rate, stop_order_execution_expression)
|
560
|
+
}
|
561
|
+
return tmp
|
562
|
+
end
|
563
|
+
|
564
|
+
#
|
565
|
+
#=== 建玉一覧を取得します。
|
566
|
+
#
|
567
|
+
#currency_pair_code:: 通貨ペアコード。<b>※未実装</b>
|
568
|
+
#戻り値:: 建玉IDをキーとするClickClientScrap::FX::OpenInterestのハッシュ。
|
569
|
+
#
|
570
|
+
def list_open_interests( currency_pair_code=nil )
|
571
|
+
result = link_click( "3" )
|
572
|
+
ClickClientScrap::Client.error( result ) if result.forms.empty?
|
573
|
+
form = result.forms.first
|
574
|
+
form["P001"] = "" # TODO currency_pair_codeでの絞り込み
|
575
|
+
result = @client.submit(form)
|
576
|
+
|
577
|
+
list = []
|
578
|
+
each_page( result ) {|page|
|
579
|
+
list += page.body.toutf8.scan( /<a href="[^"]*">([A-Z]{3}\/[A-Z]{3}):([^<]*)<\/a><br>[^;]*;<font[^>]*>([^<]*)<\/font>([\d\.]*)[^\s@]*@([\d\.]*).*?<font[^>]*>([^<]*)<\/font>/m )
|
580
|
+
}
|
581
|
+
tmp = {}
|
582
|
+
list.each {|i|
|
583
|
+
open_interest_id = i[1]
|
584
|
+
pair = to_pair( i[0] )
|
585
|
+
sell_or_buy = i[2] == "売" ? ClickClientScrap::FX::SELL : ClickClientScrap::FX::BUY
|
586
|
+
count = i[3].to_i
|
587
|
+
rate = i[4].to_f
|
588
|
+
profit_or_loss = i[5].to_i
|
589
|
+
tmp[open_interest_id] = OpenInterest.new(open_interest_id, pair, sell_or_buy, count, rate, profit_or_loss )
|
590
|
+
}
|
591
|
+
return tmp
|
592
|
+
end
|
593
|
+
|
594
|
+
# すべてのページを列挙する。
|
595
|
+
def each_page( page )
|
596
|
+
current_page=1
|
597
|
+
while ( page )
|
598
|
+
yield page
|
599
|
+
current_page+=1
|
600
|
+
link_to_next = page.links.find{|i|
|
601
|
+
i.text == current_page.to_s
|
602
|
+
}
|
603
|
+
page = link_to_next ? @client.click( link_to_next ) : nil
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
#
|
608
|
+
#=== 余力情報を取得します。
|
609
|
+
#
|
610
|
+
#戻り値:: ClickClientScrap::FX::Marginのハッシュ。
|
611
|
+
#
|
612
|
+
def get_margin
|
613
|
+
result = link_click( "7" )
|
614
|
+
list = result.body.toutf8.scan( /【([^<]*)[^>]*>[^>]*>([^<]*)</m )
|
615
|
+
values = list.inject({}) {|r,i|
|
616
|
+
if ( i[0] == "証拠金維持率】" )
|
617
|
+
r[i[0]] = i[1]
|
618
|
+
else
|
619
|
+
r[i[0]] = i[1].gsub(/,/, "").to_i
|
620
|
+
end
|
621
|
+
r
|
622
|
+
}
|
623
|
+
return Margin.new(
|
624
|
+
values["時価評価総額】"],
|
625
|
+
values["建玉評価損益】"],
|
626
|
+
values["口座残高】"],
|
627
|
+
values["証拠金維持率】"],
|
628
|
+
values["余力】"],
|
629
|
+
values["拘束証拠金】"],
|
630
|
+
values["必要証拠金】"],
|
631
|
+
values["注文中必要証拠金】"],
|
632
|
+
values["振替可能額】"]
|
633
|
+
)
|
634
|
+
end
|
635
|
+
|
636
|
+
# ログアウトします。
|
637
|
+
def logout
|
638
|
+
@client.click( @links.find {|i|
|
639
|
+
i.text == "\303\233\302\270\303\236\302\261\302\263\303\204" \
|
640
|
+
|| i.text == "ログアウト"
|
615
641
|
})
|
616
|
-
end
|
617
|
-
|
618
|
-
private
|
619
|
-
# "USD/JPY"を:USDJPYのようなシンボルに変換します。
|
620
|
-
def to_pair( str )
|
621
|
-
str.gsub( /\//, "" ).to_sym
|
622
|
-
end
|
623
|
-
|
624
|
-
# 注文種別を注文種別コードに変換します。
|
625
|
-
def
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
:
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
)
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
end
|
689
|
-
|
690
|
-
|
642
|
+
end
|
643
|
+
|
644
|
+
private
|
645
|
+
# "USD/JPY"を:USDJPYのようなシンボルに変換します。
|
646
|
+
def to_pair( str )
|
647
|
+
str.gsub( /\//, "" ).to_sym
|
648
|
+
end
|
649
|
+
|
650
|
+
# 注文種別を注文種別コードに変換します。
|
651
|
+
def to_execution_expression( execution_expression )
|
652
|
+
if execution_expression == "指"
|
653
|
+
return ClickClientScrap::FX::EXECUTION_EXPRESSION_LIMIT_ORDER
|
654
|
+
elsif execution_expression == "逆"
|
655
|
+
return ClickClientScrap::FX::EXECUTION_EXPRESSION_REVERSE_LIMIT_ORDER
|
656
|
+
else
|
657
|
+
return ClickClientScrap::FX::EXECUTION_EXPRESSION_MARKET_ORDER
|
658
|
+
end
|
659
|
+
end
|
660
|
+
|
661
|
+
# 注文種別を注文種別コードに変換します。
|
662
|
+
def to_order_type_code( order_type )
|
663
|
+
return case order_type
|
664
|
+
when "成行注文"
|
665
|
+
ClickClientScrap::FX::ORDER_TYPE_MARKET_ORDER
|
666
|
+
when "通常注文"
|
667
|
+
ClickClientScrap::FX::ORDER_TYPE_NORMAL
|
668
|
+
when "OCO注文"
|
669
|
+
ClickClientScrap::FX::ORDER_TYPE_OCO
|
670
|
+
when "IFD注文"
|
671
|
+
ClickClientScrap::FX::ORDER_TYPE_IFD
|
672
|
+
when "IFD-OCO注文"
|
673
|
+
ClickClientScrap::FX::ORDER_TYPE_IFD_OCO
|
674
|
+
else
|
675
|
+
raise "illegal order_type. order_type=#{order_type}"
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
def link_click( no )
|
680
|
+
link = @links.find {|i|
|
681
|
+
i.attributes["accesskey"] == no
|
682
|
+
}
|
683
|
+
raise "link isnot found. accesskey=#{no}" unless link
|
684
|
+
@client.click( link )
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
# オプション
|
689
|
+
attr :options, true
|
690
|
+
|
691
|
+
#=== スワップ
|
692
|
+
Swap = Struct.new(:pair, :sell_swap, :buy_swap)
|
693
|
+
#=== レート
|
694
|
+
Rate = Struct.new(:pair, :bid_rate, :ask_rate, :sell_swap, :buy_swap )
|
695
|
+
#===注文
|
696
|
+
Order = Struct.new(:order_no, :trade_type, :order_type, :execution_expression, :sell_or_buy, :pair,
|
697
|
+
:count, :rate, :order_state, :stop_order_rate, :stop_order_execution_expression )
|
698
|
+
#===注文結果
|
699
|
+
OrderResult = Struct.new(:order_no )
|
700
|
+
#===建玉
|
701
|
+
OpenInterest = Struct.new(:open_interest_id, :pair, :sell_or_buy, :count, :rate, :profit_or_loss )
|
702
|
+
#===余力
|
703
|
+
Margin = Struct.new(
|
704
|
+
:market_value, #時価評価の総額
|
705
|
+
:appraisal_profit_or_loss_of_open_interest, #建玉の評価損益
|
706
|
+
:balance_in_account, # 口座残高
|
707
|
+
:guarantee_money_maintenance_ratio, #証拠金の維持率
|
708
|
+
:margin, #余力
|
709
|
+
:freezed_guarantee_money, #拘束されている証拠金
|
710
|
+
:required_guarantee_money, #必要な証拠金
|
711
|
+
:ordered_guarantee_money, #注文中の証拠金
|
712
|
+
:transferable_money_amount #振替可能額
|
713
|
+
)
|
714
|
+
end
|
715
|
+
end
|
716
|
+
|
717
|
+
class << WWW::Mechanize::Util
|
718
|
+
def from_native_charset(s, code)
|
719
|
+
if WWW::Mechanize.html_parser == Nokogiri::HTML
|
720
|
+
return unless s
|
721
|
+
Iconv.iconv(code, "UTF-8", s).join("") rescue s # エラーになった場合、変換前の文字列を返す
|
722
|
+
else
|
723
|
+
return s
|
724
|
+
end
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
728
|
+
|