unageanu-clickclient 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,8 @@
1
+
2
+ == 0.0.2 2008-03-30
3
+
4
+ * WebサービスのURL変更に対応。
5
+
6
+ == 0.0.1 2007-12-15
7
+
8
+ * Initial release
data/License.txt ADDED
@@ -0,0 +1,57 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.co.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the GPL,
3
+ or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) rename any non-standard executables so the names do not conflict
21
+ with standard executables, which must also be provided.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or executable
26
+ form, provided that you do at least ONE of the following:
27
+
28
+ a) distribute the executables and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard executables non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under this terms.
43
+
44
+ They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
45
+ files under the ./missing directory. See each file for the copying
46
+ condition.
47
+
48
+ 5. The scripts and library files supplied as input to or produced as
49
+ output from the software do not automatically fall under the
50
+ copyright of the software, but belong to whomever generated them,
51
+ and may be sold commercially, and may be aggregated with this
52
+ software.
53
+
54
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
55
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57
+ PURPOSE.
data/README.txt ADDED
@@ -0,0 +1,24 @@
1
+ = CLICK Client -- CLICK Securities Web Service Client Library for Ruby.
2
+
3
+ CLICK Client is a CLICK Securities Web Service Client for Ruby.
4
+ CLICK Client はクリック証券Webサービスにアクセスするためのクライアントライブラリです。
5
+ 以下の機能を提供します。
6
+
7
+ * 外為証拠金取引(FX)取引
8
+
9
+ == Installation
10
+
11
+ rubygemを使ってインストール可能です。以下のコマンドを実行してインストールしてください。
12
+
13
+ % [sudo] gem install clickclient
14
+
15
+
16
+ == License
17
+
18
+ Ruby ライセンスに準拠
19
+
20
+
21
+ == Disclaimer
22
+ * 本ライブラリの利用は自己責任でお願いします。
23
+ * ライブラリの不備・不具合等によるあらゆる損害について、作成者は責任を負いません。
24
+
@@ -0,0 +1,202 @@
1
+ require File.dirname(__FILE__) + '/../lib/clickclient'
2
+
3
+ require 'kconv'
4
+
5
+ #== 利用サンプル
6
+ #ローカルサーバーに接続し、結果を表示します。
7
+ c = ClickClient::Client.new
8
+
9
+ # ローカルサーバーへの接続設定
10
+ c.host_name = "http://localhost:8000"
11
+ c.fx_path = "/webservice/ws-redirect"
12
+ c.fx_session( "012345678", "sdfsdf" ) { | fx_session |
13
+
14
+ # 通貨ペア一覧取得
15
+ # 引数で取得する通貨ペアコードを配列で指定
16
+ # 指定しない場合すべての通貨ペアの情報を取得。
17
+ puts "\n--- list_currency_pairs"
18
+ list = fx_session.list_currency_pairs [GMO::FX::USDJPY, GMO::FX::EURJPY]
19
+ list.each{ |currency_pair_code, value| puts value }
20
+
21
+ # レート一覧取得
22
+ puts "\n--- list_rates"
23
+ list = fx_session.list_rates
24
+ list.each{ |currency_pair_code, value| puts value }
25
+
26
+ # 成り行き注文
27
+ puts "\n--- order - buy"
28
+ puts fx_session.order( GMO::FX::USDJPY, GMO::FX::BUY, 2 )
29
+ puts "\n--- order - sell"
30
+ result = fx_session.order( GMO::FX::USDJPY, GMO::FX::SELL, 1, {
31
+ :slippage=>99,
32
+ :slippage_base_rate=>list[GMO::FX::USDJPY].bid_rate
33
+ })
34
+ puts result
35
+
36
+ # 成り行き決済注文
37
+ puts "\n--- settle"
38
+ puts fx_session.settle( result.order_no, 1 )
39
+ puts fx_session.settle( result.order_no, 2, {
40
+ :slippage=>99,
41
+ :slippage_base_rate=>list[GMO::FX::USDJPY].bid_rate
42
+ })
43
+
44
+ # 通常注文
45
+ puts "\n--- order - basic sell"
46
+ result = fx_session.order( GMO::FX::USDJPY, GMO::FX::SELL, 1, {
47
+ :rate=>145.19,
48
+ :execution_expression=>GMO::FX::EXECUTION_EXPRESSION_LIMIT_ORDER,
49
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
50
+ :expiration_date=>DateTime.new( 2007, 11, 5, 0 )
51
+ })
52
+ puts result
53
+
54
+ # 注文変更
55
+ puts "\n--- edit_order"
56
+ fx_session.edit_order( result.order_no, {
57
+ :rate=>145.19,
58
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_TODAY
59
+ })
60
+
61
+ # 注文取消し
62
+ puts "\n--- cancel_order"
63
+ fx_session.cancel_order( result.order_no )
64
+
65
+ # 通常決済注文
66
+ puts "\n--- settle - basic"
67
+ result = fx_session.order( GMO::FX::USDJPY, GMO::FX::SELL, 2, {
68
+ :rate=>145.19,
69
+ :execution_expression=>GMO::FX::EXECUTION_EXPRESSION_LIMIT_ORDER,
70
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_TODAY
71
+ })
72
+ puts fx_session.settle( result.order_no, 2, {
73
+ :rate=>146.20,
74
+ :execution_expression=>GMO::FX::EXECUTION_EXPRESSION_LIMIT_ORDER,
75
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
76
+ :expiration_date=>DateTime.new( 2007, 11, 5, 0 )
77
+ })
78
+
79
+ # OCO注文
80
+ puts "\n--- order - oco"
81
+ result = fx_session.order( GMO::FX::USDJPY, GMO::FX::SELL, 1, {
82
+ :rate=>145.19,
83
+ :stop_order_rate=>144.19,
84
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
85
+ :expiration_date=>DateTime.new( 2007, 11, 5, 0 )
86
+ })
87
+ puts result
88
+
89
+ # OCO注文変更
90
+ puts "\n--- edit - oco"
91
+ fx_session.edit_order( result.limit_order_no, {
92
+ :stop_order_no=>result.stop_order_no,
93
+ :rate=>145.29,
94
+ :stop_order_rate=>144.29,
95
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
96
+ :expiration_date=>DateTime.new( 2007, 11, 6, 0 )
97
+ })
98
+
99
+ # OCO決済注文
100
+ puts "\n--- settle - oco"
101
+ puts fx_session.settle( result.limit_order_no, 2, {
102
+ :rate=>146.20,
103
+ :stop_order_rate=>144.19,
104
+ :execution_expression=>GMO::FX::EXECUTION_EXPRESSION_LIMIT_ORDER,
105
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
106
+ :expiration_date=>DateTime.new( 2007, 11, 5, 0 )
107
+ })
108
+
109
+ # IFD取引
110
+ puts "\n--- order - ifd"
111
+ result = fx_session.order( GMO::FX::USDJPY, GMO::FX::SELL, 1, {
112
+ :rate=>145.19,
113
+ :execution_expression=>GMO::FX::EXECUTION_EXPRESSION_LIMIT_ORDER,
114
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
115
+ :expiration_date=>DateTime.new( 2007, 11, 5, 0 ),
116
+ :settle=>{
117
+ :unit=>1,
118
+ :sell_or_buy=>GMO::FX::BUY,
119
+ :rate=>145.91,
120
+ :execution_expression=>GMO::FX::EXECUTION_EXPRESSION_LIMIT_ORDER,
121
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
122
+ :expiration_date=>DateTime.new( 2007, 11, 5, 0 ),
123
+ }
124
+ })
125
+ puts result
126
+
127
+ # IFD注文変更
128
+ puts "\n--- edit - ifd"
129
+ fx_session.edit_order( result.order_no, {
130
+ :rate=>145.29,
131
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_TODAY,
132
+ :settle=>{
133
+ :order_no=>result.settlement_order_no,
134
+ :rate=>145.91,
135
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
136
+ :expiration_date=>DateTime.new( 2007, 11, 6, 0 ),
137
+ }
138
+ })
139
+
140
+ # IFD-OCO取引
141
+ puts "\n--- order - ifd-oco"
142
+ result = fx_session.order( GMO::FX::USDJPY, GMO::FX::SELL, 1, {
143
+ :rate=>145.19,
144
+ :execution_expression=>GMO::FX::EXECUTION_EXPRESSION_LIMIT_ORDER,
145
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_TODAY,
146
+ :settle=>{
147
+ :unit=>1,
148
+ :sell_or_buy=>GMO::FX::BUY,
149
+ :rate=>145.91,
150
+ :stop_order_rate=>144.15,
151
+ :execution_expression=>GMO::FX::EXECUTION_EXPRESSION_LIMIT_ORDER,
152
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
153
+ :expiration_date=>DateTime.new( 2007, 11, 5, 0 ),
154
+ }
155
+ })
156
+ puts result
157
+
158
+ # IFD-OCO注文変更
159
+ puts "\n--- edit - ifd-oco"
160
+ fx_session.edit_order( result.order_no, {
161
+ :rate=>145.29,
162
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
163
+ :expiration_date=>DateTime.new( 2007, 11, 6, 0 ),
164
+ :settle=>{
165
+ :order_no=>result.kessaiSashineChumonBango,
166
+ :stop_order_no=>result.kessaiGyakusashiChumonBango,
167
+ :rate=>145.21,
168
+ :stop_order_rate=>144.15,
169
+ :expiration_type=>GMO::FX::EXPIRATION_TYPE_SPECIFIED,
170
+ :expiration_date=>DateTime.new( 2007, 11, 6, 0 ),
171
+ }
172
+ })
173
+
174
+ # 注文一覧取得
175
+ # 引数で、注文状態コード(必須)、通貨ペアコード、注文日期間開始日、注文日期間終了日を指定可能。
176
+ puts "\n--- list_orders"
177
+ list = fx_session.list_orders GMO::FX::ORDER_CONDITION_ALL, GMO::FX::EURJPY, Date.new( 2007, 10, 1 ), Date.new( 2007, 11, 1 )
178
+ list.each{ |item| puts item }
179
+
180
+ # 建玉一覧取得
181
+ # 引数で、通貨ペアコードを指定可能。(省略可)
182
+ puts "\n--- list_open_interests"
183
+ list = fx_session.list_open_interests( GMO::FX::EURJPY )
184
+ list.each{ |item| puts item }
185
+
186
+ # 約定一覧取得
187
+ # 引数で、取得期間(開始日,終了日)(必須)、通貨ペアコード、取引タイプ(新規Or決済)を指定可能。
188
+ puts "\n--- list_execution_results"
189
+ list = fx_session.list_execution_results( Date.new( 2007, 10, 1 ), Date.new( 2007, 11, 1 ) )
190
+ list.each{ |item| puts item }
191
+ list = fx_session.list_execution_results( Date.new( 2007, 10, 1 ), Date.new( 2007, 11, 1 ), GMO::FX::TRADE_TYPE_NEW, GMO::FX::EURJPY )
192
+ list.each{ |item| puts item }
193
+
194
+ # 余力情報の取得
195
+ puts "\n--- get_margin"
196
+ puts fx_session.get_margin
197
+
198
+ # お知らせ一覧取得
199
+ puts "\n--- list_messages"
200
+ list = fx_session.list_messages
201
+ list.each{ |item| puts item.to_s.tosjis }
202
+ }
@@ -0,0 +1,4 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'clickclient/common'
4
+ require 'clickclient/fx'
@@ -0,0 +1,208 @@
1
+ begin
2
+ require 'rubygems'
3
+ rescue LoadError
4
+ end
5
+ require 'httpclient'
6
+ require 'rexml/document'
7
+ require 'date'
8
+
9
+ #
10
+ #=== クリック証券アクセスクライアント
11
+ #
12
+ #*Version*:: 0.0.2
13
+ #*License*:: Ruby ライセンスに準拠
14
+ #
15
+ #クリック証券Webサービスを利用するためのクライアントライブラリです。以下の機能を提供します。
16
+ #- 外為証拠金取引(FX)取引
17
+ #
18
+ #====依存モジュール
19
+ #「{httpclient}[http://dev.ctor.org/http-access2]」を利用しています。以下のコマンドを実行してインストールしてください。
20
+ #
21
+ # gem install httpclient --source http://dev.ctor.org/download/
22
+ #
23
+ #====基本的な使い方
24
+ #
25
+ # require 'clickclient'
26
+ #
27
+ # c = ClickClient::Client.new
28
+ # # c = ClickClient::Client.new https://<プロキシホスト>:<プロキシポート> # プロキシを利用する場合
29
+ # c.fx_session( "<ユーザー名>", "<パスワード>" ) { | fx_session |
30
+ # # 通貨ペア一覧取得
31
+ # list = fx_session.list_currency_pairs
32
+ # puts list
33
+ # }
34
+ #なお、ご利用にあたっては「{クリック証券Webサービス利用規約}[https://sec.gmo.jp/corp/guide/regulations/pdf/reg_webservice.pdf]
35
+ #」(PDF)に同意して頂く必要があります。
36
+ #
37
+ #====免責
38
+ #- 本ライブラリの利用は自己責任でお願いします。
39
+ #- ライブラリの不備・不具合等によるあらゆる損害について、作成者は責任を負いません。
40
+ #
41
+ module ClickClient
42
+
43
+ # クライアント
44
+ class Client
45
+
46
+ # ホスト名
47
+ DEFAULT_HOST_NAME = "https://sec-sso.click-sec.com"
48
+
49
+ #
50
+ #===コンストラクタ
51
+ #
52
+ #*proxy*:: プロキシホストを利用する場合、そのホスト名とパスを指定します。
53
+ # 例) https://proxyhost.com:80
54
+ #
55
+ def initialize( proxy=nil )
56
+ @client = HTTPClient.new( proxy, "ClickClientLib")
57
+ @client.set_cookie_store("cookie.dat")
58
+ @host_name = DEFAULT_HOST_NAME
59
+ end
60
+
61
+ #ホスト名
62
+ attr :host_name, true
63
+
64
+ private
65
+ # ログインしてブロックを実行する。ブロックの実行後ログアウトする。
66
+ def session( uri, userid, password, &block )
67
+
68
+ # sequence 1
69
+ result = @client.post(uri, "u=" << userid )
70
+ seq2_uri = result.header["Location"].to_s
71
+ raise "fail session-1.responce=" << result.content if seq2_uri == nil || seq2_uri.length <= 0
72
+
73
+ # sequence 2
74
+ result = @client.get( seq2_uri )
75
+ doc = REXML::Document.new(result.content)
76
+ unless ( doc.text( "./loginResponse/responseStatus" ) =~ /OK/ )
77
+ raise "fail session-2." << doc.text( "./loginResponse/message" )
78
+ end
79
+
80
+ # sequence 3
81
+ base_uri = File.dirname( seq2_uri )
82
+ result = @client.post( base_uri + "/ws-login", "j_username=#{userid}&j_password=#{password}" )
83
+ seq4_uri = result.header["Location"]
84
+ if ( seq4_uri == nil || seq4_uri.length <= 0 )
85
+ doc = REXML::Document.new(result.content)
86
+ raise "fail session-3." << doc.text( "./loginResponse/message" )
87
+ end
88
+
89
+ # sequence 4
90
+ # responseStatusがOKになるまでリダイレクトが続く。
91
+ while ( true )
92
+ result = @client.get( seq4_uri )
93
+ doc = REXML::Document.new(result.content)
94
+ if ( doc.text( "./loginResponse/responseStatus" ) =~ /OK/ )
95
+ break
96
+ else
97
+ seq4_uri = result.header["Location"]
98
+ raise "fail session-4.responce=" << result.content if seq4_uri == nil || seq4_uri.length <= 0
99
+ end
100
+ end
101
+
102
+ begin
103
+ block.call( @client, base_uri )
104
+ ensure
105
+ # logout
106
+ result = @client.post( base_uri + "/ws-logout" )
107
+ doc = REXML::Document.new(result.content)
108
+ unless ( doc.text( "./logoutResponse/responseStatus" ) =~ /OK/ )
109
+ raise "fail session-5." << doc.text( "./logoutResponse/message" )
110
+ end
111
+ end
112
+
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ #
119
+ #=== 結果オブジェクトの抽象基底クラス。
120
+ #
121
+ class Base #:nodoc:
122
+ def initialize( item )
123
+ # 属性と子要素の値を、オブジェクトの属性として格納する。
124
+ item.attributes.each { |name, value|
125
+ set_attribute(name.to_s ,value)
126
+ }
127
+ item.elements.each { |elm|
128
+ if ( elm.name != "responseStatus" && elm.name != "message" )
129
+ set_attribute(elm.name.to_s, elm.text)
130
+ end
131
+ }
132
+ end
133
+ def to_s
134
+ str = ""
135
+ instance_variables.each { |name|
136
+ str += name + "=" + instance_variable_get(name).to_s + ", "
137
+ }
138
+ return str.chop.chop
139
+ end
140
+ def method_missing( name, *args )
141
+ if name.to_s =~ /(.*?)=/
142
+ name = $1
143
+ setter = true
144
+ end
145
+
146
+ # 同名の属性があればそれのReaderと見なし、属性値を返す。
147
+ value = instance_variable_get("@" << name.to_s)
148
+ unless ( value == nil )
149
+ if setter
150
+ instance_variable_set( "@" << name, args[0] )
151
+ else
152
+ return value
153
+ end
154
+ else
155
+ super(name)
156
+ end
157
+ end
158
+ def hash
159
+ hash = 0
160
+ values.each {|v|
161
+ hash = v.hash + 31 * hash
162
+ }
163
+ return hash
164
+ end
165
+ def eql?(other)
166
+ return false if other == nil
167
+ return false unless other.is_a?( Base )
168
+ a = values
169
+ b = other.values
170
+ return false if a.length != b.length
171
+ a.length.times{|i|
172
+ return false unless a[i].eql? b[i]
173
+ }
174
+ return true
175
+ end
176
+ protected
177
+ def values
178
+ values = []
179
+ instance_variables.each { |name|
180
+ values << instance_variable_get(name)
181
+ }
182
+ return values
183
+ end
184
+ private
185
+ def set_attribute(name ,value)
186
+ if ( value =~ /^\d+$/)
187
+ value = value.to_i
188
+ elsif ( value =~ /^[\d\.]+$/)
189
+ value = value.to_f
190
+ elsif ( value =~ /^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}$/)
191
+ value = DateTime.strptime( value, "%Y-%m-%d %H:%M:%S")
192
+ elsif ( value =~ /^\d{4}-\d{2}-\d{2}$/)
193
+ value = DateTime.strptime( value, "%Y-%m-%d")
194
+ end
195
+ instance_variable_set( "@" << name, value )
196
+ end
197
+ end
198
+
199
+ # 結果を解析し、エラーであれば例外をスローする。
200
+ def self.parse( content )
201
+ doc = REXML::Document.new( content )
202
+ unless ( doc.text( "./*/responseStatus" ) =~ /OK/ )
203
+ raise "fail." << doc.text( "./*/message" )
204
+ end
205
+ return doc
206
+ end
207
+
208
+ end