clickclient_scrap 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|