1
1
// ==UserScript==
2
2
// @name Categorize Stocks
3
3
// @namespace https://ResolveToExcel.com/
4
- // @version 1.2 .0
4
+ // @version 1.3 .0
5
5
// @description Group and summarize stocks by category in your brokerage account
6
6
// @author Marc Page
7
7
// @match https://oltx.fidelity.com/ftgw/fbc/*
8
8
// @match https://digital.fidelity.com/ftgw/digital/portfolio/*
9
- // @match https://client.schwab.com/app/accounts/positions/*
10
9
// @grant none
11
10
// @updateURL https://raw.githubusercontent.com/marcpage/brokerage_equities_sum/main/brokerage_equities_sum.js
12
11
// @downloadURL https://raw.githubusercontent.com/marcpage/brokerage_equities_sum/main/brokerage_equities_sum.js
24
23
1.1.8 Constantly entering and leaving the input area now longer adds more blank lines (11/7/2023)
25
24
1.1.9 Remove "Account Total" as a symbol from Fidelity (11/7/2023)
26
25
1.2.0 Refactored code to be more unit-testable
26
+ 1.3.0 Removed Schwab as it was broken and show high and low for single-symbols
27
27
*/
28
28
29
29
@@ -33,12 +33,21 @@ function parse_money(money_text) {
33
33
return parseFloat ( money_text . replace ( '$' , '' ) . replace ( "," , "" ) . replace ( / ^ \s + / , "" ) . replace ( / \s + $ / , "" ) )
34
34
}
35
35
36
+ /* parses out the low and high from a range
37
+ "Low\n$67.99\nHigh\n$75.37\n"
38
+ */
39
+ function parse_range ( range_text ) {
40
+ var parts = / L o w \s + ( \$ [ 0 - 9 . , ] + ) \s + H i g h \s + ( \$ [ 0 - 9 . , ] + ) \s + / . exec ( range_text ) ;
41
+ return parts ? [ parse_money ( parts [ 1 ] ) , parse_money ( parts [ 2 ] ) ] : [ undefined , undefined ] ;
42
+ }
43
+
36
44
37
45
/* Scrapes the symbols and the value of current value of equities in the positions tab on Fidelity's site.
38
46
*/
39
47
function load_symbol_table_fidelity ( ) {
40
48
var headers = document . getElementsByClassName ( "ag-header" ) [ 0 ] . getElementsByClassName ( "ag-header-cell" ) ;
41
49
var current_value_index = Array . from ( headers ) . findIndex ( ( x ) => x . innerText . indexOf ( "Current Value" ) >= 0 ) ;
50
+ var range_value_index = Array . from ( headers ) . findIndex ( ( x ) => x . innerText . indexOf ( "52-Week Range" ) >= 0 ) ;
42
51
var rows = document . getElementsByClassName ( "ag-row" ) ;
43
52
var data = Array . from ( rows ) . filter ( e => e . getElementsByClassName ( "ag-cell" ) . length > 1 ) ;
44
53
var table = { } ;
@@ -48,6 +57,8 @@ function load_symbol_table_fidelity() {
48
57
var row = data [ row_index ] ;
49
58
var cells = row && row . getElementsByClassName ? row . getElementsByClassName ( "ag-cell" ) : undefined ;
50
59
var value_text = cells && cells . length > current_value_index ? cells [ current_value_index ] : undefined ;
60
+ var range_text = cells && cells . length > range_value_index ? cells [ range_value_index ] : undefined ;
61
+ var low_high_value = range_text ? parse_range ( range_text . innerText ) : undefined ;
51
62
var value = value_text ? parse_money ( value_text . innerText ) : undefined ;
52
63
var symbol_cell = cells ? cells [ 0 ] : undefined ;
53
64
var symbol_div = symbol_cell ? symbol_cell . getElementsByClassName ( "posweb-cell-symbol-name_container" ) : undefined ;
@@ -62,38 +73,14 @@ function load_symbol_table_fidelity() {
62
73
}
63
74
64
75
if ( symbol && value && ! symbol . match ( / A c c o u n t T o t a l / ) ) {
65
- table [ symbol ] = value ;
76
+ table [ symbol ] = [ value , low_high_value [ 0 ] , low_high_value [ 1 ] ] ;
66
77
}
67
78
}
68
79
69
80
return table ;
70
81
}
71
82
72
83
73
- /* Scrapes the symbols and the market value of equities in the positions tab on Schwab's site.
74
- */
75
- function load_symbol_table_schwab ( ) {
76
- var table = { } ;
77
- var positions = document . getElementById ( "responsiveTable" ) ;
78
- var rows = positions . getElementsByTagName ( "tr" ) ;
79
- var header_names = Array . from ( rows [ 0 ] . getElementsByTagName ( "th" ) )
80
- . map ( h => h . innerText . replace ( / ^ \s + / , "" ) . replace ( / \s + $ / , "" ) ) ;
81
- var symbol_rows = Array . from ( rows ) . filter ( r => r . getElementsByTagName ( "td" ) . length == 12 ) ;
82
- var market_value_index = Array . from ( header_names ) . findIndex ( x => x . indexOf ( "Market Value" ) >= 0 ) - 1 ;
83
-
84
- for ( var r = 0 ; r < symbol_rows . length ; ++ r ) {
85
- var symbol = symbol_rows [ r ] . getElementsByTagName ( "th" ) [ 0 ] . innerText . replace ( ',' , '' ) . replace ( / ^ \s + / , "" ) . replace ( / \s + $ / , "" ) ;
86
- var fields = symbol_rows [ r ] . getElementsByTagName ( "td" ) ;
87
- var value_text = fields [ market_value_index ] . getElementsByTagName ( "div" ) [ 0 ] . childNodes [ 0 ] . nodeValue ;
88
- var value = parse_money ( value_text ) ;
89
-
90
- table [ symbol ] = value ;
91
- }
92
-
93
- return table ;
94
- }
95
-
96
-
97
84
/* parses the user input and generates report
98
85
*/
99
86
function parse_and_add ( text , symbol_values ) {
@@ -110,26 +97,33 @@ function parse_and_add(text, symbol_values) {
110
97
111
98
output += line + "\n" ;
112
99
113
- if ( line . match ( / ^ \s * $ / ) ) {
114
- continue ;
115
- }
116
-
117
100
var symbols = line . split ( / \s + / ) ;
118
101
var total = 0.0 ;
102
+ var low = undefined ;
103
+ var high = undefined ;
104
+ var single_symbol = undefined ;
119
105
120
106
for ( var symbol_index = 0 ; symbol_index < symbols . length ; ++ symbol_index ) {
121
107
let symbol = symbols [ symbol_index ] ;
122
108
109
+ single_symbol = symbol ;
110
+
123
111
if ( ! symbol_values [ symbol ] ) {
124
112
output += "# Symbol " + symbol + " was not found\n" ;
125
113
} else {
126
- total += symbol_values [ symbol ] ;
114
+ total += symbol_values [ symbol ] [ 0 ] ;
115
+ low = symbol_values [ symbol ] [ 1 ] ;
116
+ high = symbol_values [ symbol ] [ 2 ] ;
127
117
unseen_symbols = unseen_symbols . filter ( e => e != symbol ) ;
128
118
}
129
119
}
130
120
131
121
if ( total > 0.0 ) {
132
- output += "# Total value = $" + total . toFixed ( 2 ) + "\n\n" ;
122
+ if ( symbols . length == 1 ) {
123
+ output += "# " + single_symbol + "\t" + low + "\t" + total + "\t" + high + "\n\n" ;
124
+ } else {
125
+ output += "# Total value = $" + total . toFixed ( 2 ) + "\n\n" ;
126
+ }
133
127
}
134
128
135
129
}
@@ -140,7 +134,7 @@ function parse_and_add(text, symbol_values) {
140
134
output += "# unseen: " + unseen_symbols . join ( ", " ) + "\n" ;
141
135
142
136
for ( var unseen_symbol_index = 0 ; unseen_symbol_index < unseen_symbols . length ; ++ unseen_symbol_index ) {
143
- unseen_total += symbol_values [ unseen_symbols [ unseen_symbol_index ] ] ;
137
+ unseen_total += symbol_values [ unseen_symbols [ unseen_symbol_index ] ] [ 0 ] ;
144
138
}
145
139
146
140
output += "# Total value = $" + unseen_total . toFixed ( 2 ) + "\n\n" ;
@@ -169,13 +163,6 @@ function add_up_values_fidelity() {
169
163
}
170
164
171
165
172
- /* Action to perform on Schwab's site when user leaves the text field.
173
- */
174
- function add_up_values_schwab ( ) {
175
- add_up_values ( load_symbol_table_schwab ( ) ) ;
176
- }
177
-
178
-
179
166
/* If we haven't added our text box yet to the page, add it (or re-add it if it was removed).
180
167
*/
181
168
function ensure_working_space ( ) {
@@ -201,18 +188,13 @@ function ensure_working_space() {
201
188
if ( ! legend ) {
202
189
legend = document . getElementById ( "posweb-legend-main" ) ;
203
190
}
204
- if ( ! legend ) {
205
- console . log ( "*** Fidelity legend not found" ) ;
206
- legend = document . getElementsByClassName ( "sdps-grid-container" ) [ 0 ] ;
207
- action = add_up_values_schwab ;
208
- }
209
191
if ( ! legend ) {
210
192
console . log ( "** legend not found" ) ;
211
193
return ;
212
194
}
213
195
214
196
working_space = document . createElement ( "textarea" ) ;
215
- working_space . setAttribute ( "rows" , 30 ) ;
197
+ working_space . setAttribute ( "rows" , 15 ) ;
216
198
working_space . setAttribute ( "cols" , 120 ) ;
217
199
working_space . setAttribute ( "placeholder" , "enter list of stocks (space separated), grouped on lines" ) ;
218
200
working_space . id = "working_space" ;
@@ -227,6 +209,7 @@ function ensure_working_space() {
227
209
'use strict' ;
228
210
var isMonkey = true ;
229
211
try { isMonkey = 'undefined' === typeof GM_info . script . exclude ; } catch { isMonkey = false ; }
212
+ console . log ( "isMonkey = " + isMonkey ) ;
230
213
231
214
// check every 5 seconds to make sure the text box is still there
232
215
if ( isMonkey ) {
0 commit comments