diff --git a/cmd/bfa_client/bfa_client.go b/cmd/bfa_client/bfa_client.go
index 2025016589e0d0e1ba878b3b6c24ccbb7bdad42a..4ba1ab506cb83fce825fe534cf1920980449ffb1 100644
--- a/cmd/bfa_client/bfa_client.go
+++ b/cmd/bfa_client/bfa_client.go
@@ -1,8 +1,10 @@
 package main
 
 import (
+	"encoding/json"
 	"flag"
 	"fmt"
+	"io/ioutil"
 	"log"
 	"math/big"
 	"os"
@@ -24,7 +26,7 @@ const (
 
 var (
 	url         string
-	json        bool
+	jsonOutput  bool
 	help        bool
 	flags       = flag.NewFlagSet("", flag.ExitOnError)
 	description string
@@ -57,7 +59,7 @@ var (
 )
 
 func setFlags() {
-	flags.BoolVar(&json, "json", false, "Produce salida en formato json")
+	flags.BoolVar(&jsonOutput, "json", false, "Produce salida en formato json")
 	flags.StringVar(&url, "url", "", "URL para conexión con geth. Ejemplo: '/home/bfa/bfa/network/node/geth.ipc' o 'http://localhost:8545'")
 	flags.BoolVar(&help, "h", false, "")
 	flags.BoolVar(&help, "help", false, "Muestra esta ayuda")
@@ -114,7 +116,7 @@ func proposals() {
 	defer node.Close()
 	blockNumber = node.BlockNumberInRange(blockNumber)
 	votes := node.Votes(blockNumber)
-	if json {
+	if jsonOutput {
 		util.PrintJson(votes)
 		return
 	}
@@ -169,7 +171,7 @@ func parseFormatString(s string) (format string) {
 
 func printSealers(sealers []bfa.Address) {
 	bfa.SortAddresses(sealers)
-	if json {
+	if jsonOutput {
 		util.PrintJson(sealers)
 	} else {
 		for _, sealer := range sealers {
@@ -236,7 +238,7 @@ func sealers() {
 	}
 
 	sealers := node.SealersStatus(blockNumber)
-	if json {
+	if jsonOutput {
 		util.PrintJson(sealers)
 		return
 	}
@@ -359,13 +361,13 @@ func autovote() {
 			continue
 		}
 		node.Propose(proposal, !isSealer)
-		if json {
+		if jsonOutput {
 			voted[proposal.String()] = !isSealer
 		} else {
 			fmt.Printf("Voto por %v: %v\n", proposal, !isSealer)
 		}
 	}
-	if json {
+	if jsonOutput {
 		util.PrintJson(voted)
 	}
 }
@@ -401,13 +403,13 @@ func propose() {
 			}
 		}
 		node.Propose(address, authorize)
-		if json {
+		if jsonOutput {
 			voted[address.String()] = authorize
 		} else {
 			fmt.Printf("Voto por %v: %v\n", address, authorize)
 		}
 	}
-	if json {
+	if jsonOutput {
 		util.PrintJson(voted)
 	}
 }
@@ -546,7 +548,7 @@ func transfers() {
 						src := transaction.From
 						dst := transaction.To
 						if len(set) == 0 || set[src] || set[dst] {
-							if json {
+							if jsonOutput {
 								txs = append(txs, Transfer{src, dst, transaction.Value, i})
 							} else {
 								fmt.Printf("%v -> %v: %v (%v)\n", src.Hex(), dst.Hex(), transaction.Value, transaction.BlockNumber)
@@ -566,32 +568,27 @@ func transfers() {
 			}
 		}
 	}
-	if json {
+	if jsonOutput {
 		util.PrintJson(txs)
 	}
 }
 
-func sealerstats() {
-	type Stats struct {
-		FirstSeen        int64   `json:"first_seen,omitempty"`
-		LastSeen         int64   `json:"last_seen,omitempty"`
-		FirstBlockSealed int64   `json:"first_block_sealed,omitempty"`
-		LastBlockSealed  int64   `json:"last_block_sealed,omitempty"`
-		BlocksSealed     int64   `json:"blocks_sealed"`
-		BlocksAlive      int64   `json:"blocks_alive"`
-		Availability     float64 `json:"availability"`
-		recent           bool
-	}
+// Stats collect statistics about a sealer
+type Stats struct {
+	FirstSeen        int64   `json:"first_seen,omitempty"`
+	LastSeen         int64   `json:"last_seen,omitempty"`
+	FirstBlockSealed int64   `json:"first_block_sealed,omitempty"`
+	LastBlockSealed  int64   `json:"last_block_sealed,omitempty"`
+	BlocksSealed     int64   `json:"blocks_sealed"`
+	BlocksAlive      int64   `json:"blocks_alive"`
+	Availability     float64 `json:"availability"`
+	recent           bool
+}
+
+func calculateSealerStats(url string, first int64, last int64, factor int64) (sealerStats map[bfa.Address]*Stats) {
 	var (
-		first, last, end, lastBlock int64
-		sealerStats                 map[bfa.Address]*Stats
+		lastBlock, end int64
 	)
-	description = "Calcula estadísticas de los selladores."
-	setFlags()
-	flags.Int64Var(&first, "first-block", 1, "Primer bloque del rango (Número negativo para restar del último bloque)")
-	flags.Int64Var(&last, "last-block", latest, "Último bloque del rango (-1 para especificar el último bloque)")
-	parseFlags(true)
-	url = updateURL(url)
 	node, err := bfa.Dial(url)
 	util.Check(err)
 	defer node.Close()
@@ -618,7 +615,7 @@ func sealerstats() {
 		for block := first; block < end; {
 			snapshot := node.SnapshotAtBlock(block)
 			recentsLength := int64(len(snapshot.Recents))
-			shouldHaveSealedAfter := block - 4*recentsLength
+			shouldHaveSealedAfter := block - factor*int64(len(snapshot.Signers))
 			if shouldHaveSealedAfter < 0 {
 				shouldHaveSealedAfter = 0
 			}
@@ -645,42 +642,44 @@ func sealerstats() {
 				}
 			}
 			for sealer := range snapshot.Signers {
-				stats := sealerStats[sealer]
-				stats.LastSeen = block
-				var firstSeen bool
-				if stats.FirstSeen == 0 {
-					// we have never seen this sealer before
-					fmt.Fprintf(os.Stderr, "Nuevo sellador: %v\n", sealer.Hex())
-					stats.FirstSeen = block
-					firstSeen = true
-				}
-				if !stats.recent {
-					// sealer is not in snapshot.Recents
-					if stats.FirstBlockSealed > 0 {
-						// Sealer has signed at least once, we never zero its BlocksAlive
-						if stats.LastBlockSealed > shouldHaveSealedAfter {
+				if stats, ok := sealerStats[sealer]; ok {
+					// We are only interested if the sealer is in sealersStats
+					stats.LastSeen = block
+					var firstSeen bool
+					if stats.FirstSeen == 0 {
+						// we have never seen this sealer before
+						fmt.Fprintf(os.Stderr, "Nuevo sellador: %v\n", sealer.Hex())
+						stats.FirstSeen = block
+						firstSeen = true
+					}
+					if !stats.recent {
+						// sealer is not in snapshot.Recents
+						if stats.FirstBlockSealed > 0 {
+							// Sealer has signed at least once, we never zero its BlocksAlive
+							if stats.LastBlockSealed > shouldHaveSealedAfter {
+								stats.BlocksAlive += blocksProcessed
+								continue
+							}
+						} else if stats.FirstSeen <= shouldHaveSealedAfter {
+							// Sealer has never signed since we've seen it for the first time
+							stats.BlocksAlive = 0
+						} else if !firstSeen {
+							// Sealer has never signed, but only a few blocks have passed since we've seen it for the first time
+							// and we've seen it more than once
 							stats.BlocksAlive += blocksProcessed
-							continue
+						} else {
+							stats.BlocksAlive = 1
 						}
-					} else if stats.FirstSeen <= shouldHaveSealedAfter {
-						// Sealer has never signed since we've seen it for the first time
-						stats.BlocksAlive = 0
-					} else if !firstSeen {
-						// Sealer has never signed, but only a few blocks have passed since we've seen it for the first time
-						// and we've seen it more than once
-						stats.BlocksAlive += blocksProcessed
+						continue
+					}
+					stats.recent = false
+					// sealer is in snapshot.Recents
+					if firstSeen {
+						stats.FirstSeen = stats.FirstBlockSealed
+						stats.BlocksAlive = block - stats.FirstSeen + 1
 					} else {
-						stats.BlocksAlive = 1
+						stats.BlocksAlive += blocksProcessed
 					}
-					continue
-				}
-				stats.recent = false
-				// sealer is in snapshot.Recents
-				if firstSeen {
-					stats.FirstSeen = stats.FirstBlockSealed
-					stats.BlocksAlive = block - stats.FirstSeen + 1
-				} else {
-					stats.BlocksAlive += blocksProcessed
 				}
 			}
 			lastBlock = block
@@ -703,6 +702,40 @@ func sealerstats() {
 		blocksSeen := stats.LastSeen - stats.FirstSeen + 1
 		stats.Availability = float64(stats.BlocksAlive) / float64(blocksSeen)
 	}
+	return
+}
+
+func readStatsFromFile(filename string) (sealerStats map[bfa.Address]*Stats) {
+	file, err := os.Open(filename)
+	util.Check(err)
+	defer file.Close()
+	byteBuffer, err := ioutil.ReadAll(file)
+	util.Check(err)
+	err = json.Unmarshal(byteBuffer, &sealerStats)
+	util.Check(err)
+
+	return
+}
+
+func sealerstats() {
+	var (
+		first, last, factor int64
+		jsonFile            string
+		sealerStats         map[bfa.Address]*Stats
+	)
+	description = "Calcula estadísticas de los selladores."
+	setFlags()
+	flags.Int64Var(&first, "first-block", 1, "Primer bloque del rango (Número negativo para restar del último bloque). Ignorado si se especificó 'json_file'")
+	flags.Int64Var(&last, "last-block", latest, "Último bloque del rango (-1 para especificar el último bloque). Ignorado si se especificó 'json_file'")
+	flags.Int64Var(&factor, "factor", 2, "Bloques necesarios para declarar un nodo como no activo, especificados como múltiplos de la cantidad de selladores")
+	flags.StringVar(&jsonFile, "json-file", "", "Lee los datos de un archivo en lugar de recorrer la cadena")
+	parseFlags(true)
+	url = updateURL(url)
+	if len(jsonFile) > 0 {
+		sealerStats = readStatsFromFile(jsonFile)
+	} else {
+		sealerStats = calculateSealerStats(url, first, last, factor)
+	}
 	util.PrintJson(sealerStats)
 }