1#!/usr/bin/perl -w
2
3#
4# Initial version based on NSEIndia.pm
5#
6
7package Finance::Quote::BSEIndia;
8require 5.010;
9
10use strict;
11use POSIX qw(strftime);
12use IO::Uncompress::Unzip qw(unzip $UnzipError);
13
14our $VERSION = '1.51'; # VERSION
15
16use vars qw($BSE_URL);
17$BSE_URL = "https://www.bseindia.com";
18
19my $cachedir = $ENV{TMPDIR} // $ENV{TEMP} // '/tmp/';
20my $BSE_ZIP = $cachedir.'bseindia.zip';
21my $BSE_CSV = $cachedir.'bseindia.csv';
22
23sub methods { return ( 'india' => \&bseindia,
24                       'bseindia' => \&bseindia ); }
25
26sub labels {
27    my @labels = qw/close last high low open prevclose exchange name/;
28    return (
29    india => \@labels,
30    bseindia => \@labels
31    );
32}
33
34sub bseindia {
35    my $quoter = shift;
36    my @symbols = @_;
37    return unless @symbols;
38
39    my (%info, $errormsg, $fh, $ua, $url, $reply);
40
41    $ua = $quoter->user_agent;
42    # Set the ua to be blank. Server blocks default useragent.
43    $ua->agent('');
44
45    # Try to fetch last 10 days
46    for (my ($days, $now) = (0, time()); $days < 10; $days++) {
47        # Ex: https://www.bseindia.com/download/BhavCopy/Equity/EQ_ISINCODE_150520.zip
48        my @lt = localtime($now - $days*24*60*60);
49        my ($date, $url);
50        $date = strftime "%d%m%y", @lt;
51        $url = $BSE_URL . "/download/BhavCopy/Equity/EQ_ISINCODE_${date}.zip";
52        $reply = $ua->mirror($url, $BSE_ZIP);
53        # print "$url", $reply->is_success, $reply->status_line, "\n"; #DEBUG
54        if ($reply->is_success or $reply->code == 304) {
55            last;
56        }
57    }
58
59    if (!$reply->is_success  and  $reply->code != 304) {
60        $errormsg = "HTTP failure : " . $reply->status_line;
61    }
62
63    if (!$errormsg) {
64        if (! unzip $BSE_ZIP => $BSE_CSV) {
65            $errormsg = "Unzip error : $UnzipError";
66        }
67    }
68
69    if (!$errormsg) {
70        if (! open $fh, '<', $BSE_CSV) {
71            $errormsg = "CSV open error: $!";
72        }
73    }
74
75    if ($errormsg) {
76        foreach my $symbol (@symbols) {
77        $info{$symbol, "success"} = 0;
78        $info{$symbol, "errormsg"} = $errormsg;
79    }
80    return wantarray() ? %info : \%info;
81    }
82
83    # Create a hash of all stocks requested
84    my %symbolhash;
85    foreach my $symbol (@symbols)
86    {
87    $symbolhash{$symbol} = 0;
88    }
89    my $csvhead;
90    my @headhash;
91
92    # SC_CODE,SC_NAME,SC_GROUP,SC_TYPE,OPEN,HIGH,LOW,CLOSE,LAST,PREVCLOSE,NO_TRADES,NO_OF_SHRS,NET_TURNOV,TDCLOINDI,ISIN_CODE,TRADING_DATE,FILLER2,FILLER3
93    $csvhead = <$fh>;
94    chomp $csvhead;
95    @headhash = split /\s*,s*/, $csvhead;
96    while (<$fh>) {
97    my @data = split /\s*,s*/;
98    my %datahash;
99    my $symbol;
100    @datahash{@headhash} = @data;
101    if (exists $symbolhash{$datahash{"SC_CODE"}}) {
102        $symbol = $datahash{"SC_CODE"};
103    }
104    elsif(exists $symbolhash{$datahash{"ISIN_CODE"}}) {
105        $symbol = $datahash{"ISIN_CODE"};
106    }
107    else {
108        next;
109    }
110    $info{$symbol, 'symbol'} = $symbol;
111    $info{$symbol, 'close'} = $datahash{"CLOSE"};
112    $info{$symbol, 'last'} = $datahash{"LAST"};
113    $info{$symbol, 'high'} = $datahash{"HIGH"};
114    $info{$symbol, 'low'} = $datahash{"LOW"};
115    $info{$symbol, 'open'} = $datahash{"OPEN"};
116    $info{$symbol, 'prevclose'} = $datahash{"PREVCLOSE"};
117    $info{$symbol, 'name'} = $datahash{"SC_NAME"};
118    $quoter->store_date(\%info, $symbol, {eurodate => $datahash{"TRADING_DATE"}});
119    $info{$symbol, 'method'} = 'bseindia';
120    $info{$symbol, 'currency'} = 'INR';
121    $info{$symbol, 'exchange'} = 'BSE';
122    $info{$symbol, 'success'} = 1;
123    }
124    close($fh);
125
126    foreach my $symbol (@symbols) {
127        unless (exists $info{$symbol, 'success'}) {
128        print "$symbol not found\n";
129        $info{$symbol, 'success'} = 0;
130        $info{$symbol, 'errormsg'} = 'Stock not found on BSE.';
131    }
132    }
133
134    return wantarray ? %info : \%info;
135}
136
137
1381;
139
140
141=head1 NAME
142
143Finance::Quote::BSEIndia - Obtain quotes from BSE (India).
144
145=head1 SYNOPSIS
146
147  use Finance::Quote;
148
149  $q = Finance::Quote->new();
150
151  %info = $q->fetch('bseindia', 'INE001A01036'); # Only query BSE.
152  %info = $q->fetch('india', 'INE001A01036'); # Failover to other sources OK.
153
154=head1 DESCRIPTION
155
156This module obtains information about shares listed on the BSE (India).
157Source is the daily bhav copy (zipped CSV).
158
159This module provides both the "bseindia" and "india" fetch methods. Please use the "india" fetch method if you wish to have failover with other sources for Indian stocks (such as NSE).
160
161=head1 LABELS RETURNED
162
163The following labels may be returned by Finance::Quote::BSEIndia:
164close, last, high, low, open, prevclose, exchange, name
165
166=head1 SEE ALSO
167
168BSE (formerly known as Bombay Stock Exchange Ltd.), http://www.bseindia.com/
169
170=cut
171