-
Notifications
You must be signed in to change notification settings - Fork 1
/
ParserOperacao.fs
96 lines (87 loc) · 2.99 KB
/
ParserOperacao.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
module MinhaCarteira.ParserOperacao
open System
open MinhaCarteira.Models
open System.Linq
let getTicker mapping =
let tickerByOld =
mapping
|> Seq.collect(fun (current, olds) ->
olds
|> Seq.map(fun old -> old, current))
|> dict
fun (ticker:string) ->
let cleaned = ticker.TrimEnd('F')
match tickerByOld.TryGetValue cleaned with
| true, x -> if ticker.EndsWith('F') then x + "F" else x
| _ -> ticker
let parseLine config (lineNumber: int, line: string) =
let columns = line.Replace(';', '\t').Split('\t') |> Array.map (fun x -> x.Trim())
let culture = config.Culture
let getTicker = config.GetTicker
try
let dtNegociacao = DateTime.Parse(columns[0], culture)
let conta = Int32.Parse( columns[1], culture)
let ativo = columns[2].Replace("\"", String.Empty).Trim().ToUpper() |> getTicker
let operation =
if columns[3].Equals("SPLIT", StringComparison.InvariantCultureIgnoreCase) then
Split {
DtNegociacao = dtNegociacao
Conta = conta
Ativo = ativo
Quantidade = Decimal.Parse(columns[4], culture)
}
elif columns[3].Equals("INPLIT", StringComparison.InvariantCultureIgnoreCase) then
Inplit {
DtNegociacao = dtNegociacao
Conta = conta
Ativo = ativo
Quantidade = Decimal.Parse(columns[4], culture)
}
else
Trade {
DtNegociacao = dtNegociacao
Conta = conta
Ativo = ativo
Preco = Decimal.Parse(columns[3], culture)
QuantidadeCompra = Int32.Parse(columns[4], culture)
QuantidadeVenda = Int32.Parse(columns[5], culture)
}
Ok operation
with ex ->
(lineNumber, line, ex) |> InvalidCSV |> Error
|> Result.bind (function
op ->
match op with
| Trade t when t.QuantidadeCompra > 0 && t.QuantidadeVenda > 0 ->
Some "não pode comprar e vender na mesma operação"
| Split s when s.Quantidade < 2m ->
Some "fator de proporção do split nao pode ser menor que 2"
| _ -> None
|> function
| None -> Ok op
| Some errorMsg ->
(lineNumber, op, errorMsg)
|> InvalidOperation
|> Error
)
let split results =
let bons, erros = ResizeArray<_>(), ResizeArray<_>()
for item in results do
match item with
| Ok x -> bons.Add x
| Error x -> erros.Add x
bons :> seq<_>, erros :> seq<_>
let parseCSV config lines =
let isValidLine (_, text) =
let isInvalid = String.IsNullOrWhiteSpace(text) || text.TrimStart().StartsWith("#")
not isInvalid
let lineNumbers: seq<int> =
(1, Seq.length lines)
|> Enumerable.Range
let ops =
lines
|> Seq.zip lineNumbers
|> Seq.skip 1 // header
|> Seq.where isValidLine
|> Seq.map (parseLine config)
ops